行为差异(GCC 和 Visual C++)
考虑以下代码。
#include <stdio.h>
#include <vector>
#include <iostream>
struct XYZ { int X,Y,Z; };
std::vector<XYZ> A;
int rec(int idx)
{
int i = A.size();
A.push_back(XYZ());
if (idx >= 5)
return i;
A[i].X = rec(idx+1);
return i;
}
int main(){
A.clear();
rec(0);
puts("FINISH!");
}
我无法弄清楚代码在 Linux 上出现分段错误的原因(使用的 IDE:代码::Blocks),而在 Windows 上(使用的 IDE:Visual C++ )事实并非如此。
当我使用 Valgrind 只是为了检查实际问题是什么时,我得到了此输出。
我在四个不同的地方得到了Invalid write of size 4
。那为什么我使用Visual C++时代码没有崩溃呢?
我错过了什么吗?
Consider the following code.
#include <stdio.h>
#include <vector>
#include <iostream>
struct XYZ { int X,Y,Z; };
std::vector<XYZ> A;
int rec(int idx)
{
int i = A.size();
A.push_back(XYZ());
if (idx >= 5)
return i;
A[i].X = rec(idx+1);
return i;
}
int main(){
A.clear();
rec(0);
puts("FINISH!");
}
I couldn't figure out the reason why the code gives a segmentation fault on Linux (IDE used: Code::Blocks) whereas on Windows (IDE used: Visual C++) it doesn't.
When I used Valgrind just to check what actually the problem was, I got this output.
I got Invalid write of size 4
at four different places. Then why didn't the code crash when I used Visual C++?
Am I missing something?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您正在使用 int i = A.size()
,然后您将结构索引为数组,但使用大小值。您需要将其减少 1,例如
A[i-1].X = rec(idx+1);
啊我的错误 - 我没有考虑到矢量推回。
You're using
int i = A.size()
And then you're indexing your struct as an array, but using the size value. You need to reduce it by 1 e.g.
A[i-1].X = rec(idx+1);
Ah my mistake - I didn't take account of the vector push_back.
当您为向量赋值时,对
rec()
的递归调用可能会修改该向量。如果替换
为
会发生什么?
另外,总结一下有用的注释:
=
操作的操作数求值顺序未指定,并且由于未预先分配向量,因此在递归调用rec() 期间可能会发生多次调整大小
,从而使向量中的值的任何迭代器无效。The recursive call to
rec()
might modify the vector while you're assigning a value to it.What happens if you replace
with
?
Also, just to summarize the useful comments: the operand evaluation order of a
=
operation is unspecified and since the vector wasn't preallocated, several resizes can occur during a recursive call torec()
, thus invalidating any iterator to values in the vector.当我运行该代码时,我收到“*对象 0x300180 的错误:已释放对象的校验和不正确 - 对象可能在释放后被修改。*”。
我记得,
A[i].X = rec(idx+1)
有三个序列点。当在A上调用operator[]时,当调用rec时,以及在最后。但前两者的顺序未指定。所以如果g++先计算A[i]
,然后调用rec(idx+1)
,那么当rec
返回返回的引用时code>A[i]
可能因向量内部存储器的重新分配而失效。在 VC++ 下,它可能首先评估rec(idx+1)
,因此所有push_back
调用都是预先完成的,这意味着A[i]< /code> 调用引用正确的内存块。或者,它可能以相同的方式做事,而你只是碰巧没有出现段错误......这是未定义行为的问题之一。
更改 std::vectorA; 到
std::vectorA(10);
将为 10 个元素保留足够的空间。这可以防止您的rec
的特定实现需要重新分配,并且修复了我这边的错误。I get "* error for object 0x300180: incorrect checksum for freed object - object was probably modified after being freed. *" when I run that code.
As I recall,
A[i].X = rec(idx+1)
has three sequence points. When operator[] is called on A, when rec is called, and at the end. But the order of the first two is unspecified. So if g++ calculatesA[i]
first, and then callsrec(idx+1)
, then whenrec
returns the reference returned byA[i]
could have been invalidated by a reallocation of the vector's internal memory. Under VC++, it might be evaluatingrec(idx+1)
first, so all thepush_back
calls are done up front, which means theA[i]
calls refer to the correct block of memory. Alternatively, it might do things the same way, and you just happen to not segfault... that's one of the problems of undefined behavior.Changing
std::vector<XYZ> A;
tostd::vector<XYZ> A(10);
will reserve enough space for 10 elements. This prevents your specific implementation ofrec
from ever needing to reallocate, and that fixes the error on my end.