超过向量不会导致段错误
Posted
技术标签:
【中文标题】超过向量不会导致段错误【英文标题】:exceeding vector does not cause seg fault 【发布时间】:2015-09-30 02:48:30 【问题描述】:我对这段代码的结果感到非常困惑:
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
在reserve(1)
之后。但是,为什么填充了一个单元格后仍然是0
。我期望1
作为结果,因为end()
现在应该将迭代器返回到第二个内部数组单元格。
此外,为什么我在使用v[9] = 0
访问第十个单元格时没有遇到段错误,而向量只有 1 个单元格长?
【问题讨论】:
【参考方案1】:首先,end()
为您提供了一个迭代器,指向向量中最后一个元素之外的元素。如果向量为空,则begin()
不能返回与end()
相同的值。
然后,当您调用 reserve()
时,您实际上并没有创建任何元素,您只是保留了一些内存,因此当您添加元素时,向量不必重新分配。
最后,当你这样做时
v[9] = 0;
您正在索引向量越界,当您写入不属于您的内存时,这会导致未定义的行为。 UB 经常导致崩溃,但它并没有,它可能似乎在实际上不起作用。
作为最后一部分的注释,the []
operator 没有边界检查,这就是它接受越界索引的原因。如果你想要边界检查,你应该使用at()
。
【讨论】:
啊,好的,那么索引运算符不会影响向量的迭代器。谢谢!【参考方案2】: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
时,你认为vector应该做什么?在将第 10 个元素设置为 0
之前,它必须先推送 10 个元素。以及如何设置它们的值?全部0
?所以,它不会这样做,这取决于你自己。
【讨论】:
谢谢,但是为什么 v[index] 不创建元素呢? @lotolmencre 想一想请求 v[678] 的乐趣。向量必须首先从 0 到 677。这些新元素有什么价值?【参考方案3】:这是一个猜测,但希望对您有所帮助。
只有当您尝试访问尚未分配给进程内存空间的地址时,您才会收到段错误。当操作系统为程序提供内存时,它通常以 4KB 为增量。因此,您可以访问 一些 数组/向量的末尾而不触发段错误,但不能访问其他数组/向量。
【讨论】:
另外,我至少在 Windows7 上发现,只有前 64KB 被标记为故障,所以如果您访问 64KB+1,则没有 seg 故障。我有一个不幸的问题,我的一个状态类在它的开头有一个非常大的缓冲区,所有附属状态变量都在缓冲区之后。(MyClass*)(NULL)->m_uVariableBeyond64KBOffset
不会导致错误。以上是关于超过向量不会导致段错误的主要内容,如果未能解决你的问题,请参考以下文章