写入 std::vector 的保留空间会导致分段错误吗?



我希望这不是一个太有争议的问题,但我找不到关于SO的适当完整答案。这也不是关于reserveresize方法之间的区别或capacitysize之间的区别的问题,这对我来说(希望)很清楚,并且经常被问到SO。此外,这不是一个问题,如果这是好的做法,但事实并非如此!

请考虑以下情况:

#include <vector>
#include <iostream>
struct Foo
{
double a, b;
};
int main(int argc, char* argv[])
{
std::vector<Foo> Vec;
Vec.reserve(100);
Foo foo;
foo.a = -13.131;
foo.b = 3.141;
for(int i = 0; i < 100; ++i)
Vec[i] = foo;
for(int i = 0; i < 100; ++i)
std::cout << Vec[i].a << std::endl;
return 0;
}

我首先创建了一个 Foo 和保留内存std::vector,但不调整矢量的大小。显然size() = 0,但是 100 个元素的内存已经分配,现在可以由我的程序自由使用,所以从技术上讲,从内存中写入和读取这些元素的任何位置都不能导致分段错误,对吗?

我尝试在 Ubuntu 14.04 上运行此代码,并且一切按预期工作,所有 100 个元素都已成功写入,所有输出也是 -13.131,即使向量大小保持在 0。如果我在 SO 上寻找许多答案,它们都正确地指出它会导致未定义的行为,因为元素没有初始化,但它实际上会导致以任何方式导致分割错误(不是谈论访问向量中单位化指针的元素等)?

这里提出了一个类似的问题,这似乎证实了我的想法,但它原则上是否适用于所有支持C++编译的平台?

一旦你有未定义的行为,它就是未定义的行为。 未定义行为的一个关键方面是,您无法确定不同系统和编译器上的行为是什么。现在,您可以查看特定编译器和特定库实现的代码,您将看到它按预期运行。

但我认为你不会找到任何愿意打赌这将适用于所有不同系统、编译器和库实现的人。

例如,如果特定的矢量实现决定将保留内存用于内部信息怎么办?也许不太可能,但你怎么能确定没有系统真正这样做呢?

让我们考虑一个具体的例子 - std::vector 实现,当调用 reserve() 时,它会分配内存,但随后开始在后台线程上执行复制 - 因为它可以...耸耸肩谁知道在不久的将来会发生什么! 因此,在复制时,所有读取都将解锁并直接进入旧内存区域,因为这仍然有利于读取。

现在尝试读取超出范围的内容将尝试读取随机内存,而不是您断言的应该是新分配的内存。

因此,正如评论和其他答案所说,未定义就是未定义。

相关内容

  • 没有找到相关文章

最新更新