Mad*_*iya 31 c++ stdvector undefined-behavior
当我clear()在a上使用std::vector它时,它应该销毁它中的所有元素vector,而不是它.
示例代码:
vector<double> temp1(4);
cout << temp1.size() << std::endl;
temp1.clear();
cout << temp1.size() << std::endl;
temp1[2] = 343.5; // I should get segmentation fault here ....
cout << "Printing..... " << temp1[2] << endl;
cout << temp1.size() << std::endl;
Run Code Online (Sandbox Code Playgroud)
现在,我应该在尝试访问已清除的向量时遇到分段错误,但是它会填充那里的值(据我说这是非常错误的)
结果如下:
4
0
Printing..... 343.5
0
Run Code Online (Sandbox Code Playgroud)
这是正常的吗?这是一个非常难以发现的错误,它基本上杀了我的代码数月.
Ker*_* SB 76
您无权获得分段错误.就此而言,分段错误甚至不是C++的一部分.您的程序正在从向量中删除所有元素,并且您非法访问容器超出范围.这是未定义的行为,这意味着任何事情都可能发生.确实发生了一些事情.
小智 29
当您在向量的边界外访问时,您将获得未定义的行为.这意味着一切都会发生.任何东西.
所以你可以得到旧值,垃圾或seg-fault.你不能依赖任何东西.
如果要进行边界检查,请使用at()成员函数而不是operator [].它将抛出异常而不是调用未定义的行为.
0x4*_*2D2 27
从cppreference:
Run Code Online (Sandbox Code Playgroud)void clear();从容器中删除所有元素.使引用包含元素的任何引用,指针或迭代器无效.可能使任何过去的迭代器无效.许多实现在调用之后不会释放已分配的内存
clear(),从而有效地保持向量的容量不变.
所以没有明显问题的原因是因为向量仍然具有存储中可用的存储器.当然,这只是特定于实现的,但不是错误.此外,正如其他答案所指出的那样,您的程序也确实具有未定义的行为以便首先访问已清除的内容,因此技术上任何事情都可能发生.
让我们想象你是富有的(也许你是或者你不是......无论如何)!
由于你很富裕,你可以在Moorea(法国波利尼西亚向风群岛)购买一片土地.你非常肯定这是一个不错的财产,所以你在那个岛上建造一个别墅,你住在那里.你的别墅有游泳池,网球场,大车库和更好的东西.
过了一段时间,你离开了Moorea,因为你认为它变得非常无聊.很多运动但人很少.你出售你的土地和别墅,并决定搬到别的地方.
如果你回来一段时间后你可能会遇到很多不同的事情,但你甚至不能确定其中一个.
谁知道?虽然别墅可能不再属于你,但你甚至可以跳进游泳池或再次打网球.旁边还有另一个别墅,您可以在更大的游泳池游泳,没有人分散您的注意力.
如果你再次回来,你无法保证发现你会发现什么,而且你的矢量包含了我所看到的实现中的三个指针:(名称可能不同,但功能大致相同) .)
begin 指向分配的内存位置的开始(即X)end 它指向分配的内存+1的结尾(即开始+4)last 它指向容器+1中的最后一个元素(即开始+4)通过调用清除容器可能会破坏所有元素并重置last = begin;.该函数size()最有可能return last-begin;,因此您将观察容器大小为0.尽管如此,begin可能仍然有效并且可能仍然分配了内存(end可能仍然是begin+4).您甚至可以在clear()之前观察您设置的值.
std::vector<int> a(4);
a[2] = 12;
cout << "a cap " << a.capacity() << ", ptr is " << a.data() << ", val 2 is " << a[2] << endl;
a.clear();
cout << "a cap " << a.capacity() << ", ptr is " << a.data() << ", val 2 is " << a[2] << endl;
Run Code Online (Sandbox Code Playgroud)
打印:
a cap 4,ptr是00746570,val 2是12
a cap 4,ptr是00746570,val 2是12
你为什么不观察到任何错误?这是因为std::vector<T>::operator[]不执行任何超出界限的检查(与之相反std::vector<T>::at()).由于C++不包含"段错误",因此您的程序似乎运行正常.
注意:在MSVC 2012上,operator[]如果在调试模式下编译,则执行边界检查.
欢迎来到未定义行为的土地!事情可能会也可能不会发生.你可能甚至无法对单一情况采取任何措施.您可以冒险并大胆地查看它,但这可能不是生成可靠代码的方法.
这operator[]是有效的,但需要付出代价:它不执行边界检查.
有一种更安全而有效的方法来访问矢量,比如迭代器等.
如果你需要一个随机访问的向量(即并不总是顺序),要么对你编写程序的方式要非常小心,要么使用效率较低的数据at(),这在相同的条件下会抛出异常.
| 归档时间: |
|
| 查看次数: |
4310 次 |
| 最近记录: |