超过向量不会导致段错误

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() 不是指向内部数组的末尾而是最后一个被占用的单元格...好的,这就是为什么迭代器减法的结果仍然是0reserve(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_backresize

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)-&gt;m_uVariableBeyond64KBOffset 不会导致错误。

以上是关于超过向量不会导致段错误的主要内容,如果未能解决你的问题,请参考以下文章

C++:大的多维向量导致段错误

C++ 为啥在向量段错误中放置对象?

c++ 类向量中的段错误

OpenCV 分配导致 std::thread::join 中的段错误

带有向量向量的段错误

尝试访问向量中对象中的字段时出现段错误