我对这段代码的结果感到非常困惑:
std::vector<int> v;
std::cout << (v.end() - v.begin()) << std::endl;
v.reserve(1);
std::cout << (v.end() - v.begin()) << std::endl;
v[9] = 0;
std::cout << (v.end() - v.begin()) << std::endl;
输出:
0
0
0
所以......首先...... end()
并没有指向内部数组的末尾,而是指向最后一个被占用的单元格......好吧,这就是为什么迭代器减法的结果仍然是{在0
之后{1}}。但是,为什么在填充一个单元格之后它仍然是reserve(1)
。我期望0
作为结果,因为1
现在应该将迭代器返回到第二个内部数组单元格。
此外,为什么我在end()
访问第十个单元格时没有遇到段错误,而向量只有1个单元长?
答案 0 :(得分:4)
首先,end()
为你提供了一个超出向量中最后一个元素的迭代器。如果向量为空,则begin()
不能返回除{{1}}之外的其他内容。
然后当你调用reserve()
时实际上并没有创建任何元素时,你只保留一些内存,这样当你添加元素时,向量不必重新分配。
最后,当你做
时{{1}}
您正在索引向量越界,当您写入您不拥有的内存时,这会导致未定义的行为。 UB经常导致崩溃,但它没有,它可能似乎工作,而实际上它没有。
作为最后一部分的注释,the []
operator没有边界检查,这就是为什么它会接受超出范围的索引。如果你想要边界检查,你应该使用at()
。
答案 1 :(得分:1)
这是猜测,但希望是有用的。
当您尝试访问尚未分配给进程内存空间的地址时,您将只获得段错误。当OS为程序提供内存时,通常以4KB为增量。因此,您可以在不触发段错误的情况下访问某些数组/向量的末尾,而不会触发其他段。
答案 2 :(得分:1)
v[9] = 0;
,您只需访问该向量,即UB。在某些情况下可能会崩溃,也可能不会崩溃。没有任何保证。
v[9] = 0;
,您根本不添加元素。您需要使用push_back
或resize
:
v.push_back(0); // now it has 1 element
v.resize(10); // now it has 10 elements
修改的
为什么v [index]没有创建元素?
因为std::vector::operator[]没有做到这一点。
返回对指定位置pos处元素的引用。不执行边界检查。 与std :: map :: operator []不同,此运算符从不将新元素插入容器中。
因此,假设向量具有足够的下标运算符元素。
顺便说一句:你在写v[9] = 0
时应该怎么做?在将第10个元素设置为0
之前,必须首先推送10个元素。以及如何设定自己的价值观?全部0
?所以,它不会这样做,问题只取决于你自己。