行为差异(GCC 和 Visual C++)

发布于 2024-09-01 00:42:37 字数 819 浏览 9 评论 0原文

考虑以下代码。

#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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

℉絮湮 2024-09-08 00:42:38

您正在使用 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.

蓝天 2024-09-08 00:42:37

当您为向量赋值时,对 rec() 的递归调用可能会修改该向量。

如果替换

A[i].X = rec(idx+1);

int tmp = rec(idx+1);
A[i].X = tmp;

会发生什么?

另外,总结一下有用的注释:= 操作的操作数求值顺序未指定,并且由于未预先分配向量,因此在递归调用 rec() 期间可能会发生多次调整大小,从而使向量中的值的任何迭代器无效。

The recursive call to rec() might modify the vector while you're assigning a value to it.

What happens if you replace

A[i].X = rec(idx+1);

with

int tmp = rec(idx+1);
A[i].X = tmp;

?

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 to rec(), thus invalidating any iterator to values in the vector.

海风掠过北极光 2024-09-08 00:42:37

当我运行该代码时,我收到“*对象 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++ calculates A[i] first, and then calls rec(idx+1), then when rec returns the reference returned by A[i] could have been invalidated by a reallocation of the vector's internal memory. Under VC++, it might be evaluating rec(idx+1) first, so all the push_back calls are done up front, which means the A[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; to std::vector<XYZ> A(10); will reserve enough space for 10 elements. This prevents your specific implementation of rec from ever needing to reallocate, and that fixes the error on my end.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文