Visual Studio 2010 C++运行时错误

发布于 2024-11-05 16:25:34 字数 645 浏览 1 评论 0原文

我在 Visual Studio 2010 C++ 编译器中遇到了奇怪的行为。 以下代码编译但执行后抛出“调试断言失败” 信息:

“_BLOCK_TYPE_IS_VALID(pHead->nBlockUse)”

在GCC下编译并顺利运行。是我的错吗?

#include <iostream>
#include <vector>


using namespace std;

typedef unsigned int uint;


class Foo {
    vector<int*> coll;
public:

    void add(int* item) {
       coll.push_back(item);
    }

    ~Foo() {
        for (uint i = 0; i < coll.size(); ++i) {
            delete coll[i];
            coll[i] = NULL;
        }
    }
};

int main()
{
   Foo foo;
   foo.add(new int(4));
   Foo bar = foo;

   return 0;
}

I came across strange behavior in Visual Studio 2010 C++ compiler.
Following code compiles but throws "Debug assertion failed" after execution with
message:

"_BLOCK_TYPE_IS_VALID(pHead->nBlockUse)"

Compiles and runs smoothly under GCC. Is it my fault?

#include <iostream>
#include <vector>


using namespace std;

typedef unsigned int uint;


class Foo {
    vector<int*> coll;
public:

    void add(int* item) {
       coll.push_back(item);
    }

    ~Foo() {
        for (uint i = 0; i < coll.size(); ++i) {
            delete coll[i];
            coll[i] = NULL;
        }
    }
};

int main()
{
   Foo foo;
   foo.add(new int(4));
   Foo bar = foo;

   return 0;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

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

发布评论

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

评论(4

番薯 2024-11-12 16:25:34

您没有实现复制构造函数和复制赋值运算符(请参阅三规则)。这会导致向量中指针的浅拷贝,从而导致双重删除和断言。编辑:双重删除是未定义的行为,因此 VS 和 gcc 在这里都是正确的,他们可以做任何他们想做的事情。

通常,当您实现具有重要行为的析构函数时,您还需要编写或禁用复制构造和复制分配。

但是,在您的情况下,您真的需要通过指针存储项目吗?如果没有,只需按值存储它们即可解决问题。否则,如果您确实需要指针,请使用 shared_ptr (来自您的编译器或 boost)而不是原始指针,这样您就无需编写自己的析构函数/复制方法。

编辑:关于您的接口的进一步说明:像这样转移传入指针的所有权的接口可能会导致使用您的类的人感到困惑。如果有人传入了一个未在堆上分配的 int 的地址,那么你的析构函数仍然会失败。更好的方法是如果可能的话按值接受,或者克隆传入的项目,在 add 函数中自己调用 new

You didn't implement a copy constructor and copy assignment operator (see rule of three). This results in a shallow copy of the pointers in your vector, causing a double delete and the assertion. EDIT: Double delete is undefined behavior so both VS and gcc are correct here, they're allowed to do whatever they want.

Typically when you implement a destructor with non-trivial behavior you'll also need to write or disable copy construction and copy assignment.

However in your case do you really need to store the items by pointer? If not, just store them by value and that would fix the problem. Otherwise if you do need pointers use shared_ptr (from your compiler or boost) instead of raw pointers to save you from needing to write your own destructor/copy methods.

EDIT: A further note about your interface: Interfaces like this that transfer ownership of passed in pointers can cause confusion by people using your class. If someone passed in the address of an int not allocated on the heap then your destructor will still fail. Better is to either accept by value if possible, or clone the passed in item making your own call to new in the add function.

给不了的爱 2024-11-12 16:25:34

您删除了 item 两次,因为该行

Foo bar = foo;

调用了默认的复制构造函数,它复制了 itempointer,而不是分配和复制数据。

You're deleting item twice, because the line

Foo bar = foo;

Invokes the default copy constructor, which duplicates the itempointer, rather than allocating and copying the data.

陈独秀 2024-11-12 16:25:34

问题是 barfoo 成员的向量元素是相同的。当 foo 超出范围时,它的析构函数被调用,该函数会释放指针,使 bar 向量元素悬空。bar 析构函数尝试释放它的向量元素它悬空并导致运行时错误。您应该编写一个复制构造函数。

Foo bar = foo; // Invokes default copy constructor.

编辑1:查看此线程以了解三法则

The problem is both the bar and foo member's vector element is same. When foo goes out of scope it's destructor is called which deallocates the pointer leaving the bar vector element dangling.bar destructor tries to deallocate it's vector element which was left dangling and is causing you the runtime error. You should write a copy constructor.

Foo bar = foo; // Invokes default copy constructor.

Edit 1: Look at this thread to know about Rule of three

月依秋水 2024-11-12 16:25:34

这里更简单的解决方案是首先不使用 int*

#include <iostream>
#include <vector>


using namespace std;

typedef unsigned int uint;


class Foo {
    vector<int> coll; // remove *
public:

    void add(int item) { // remove *
       coll.push_back(item);
    }

    // remove ~Foo
};

int main()
{
   Foo foo;
   foo.add(4); // remove `new` call
   Foo bar = foo;

   return 0;
}

一般来说,尽量避免new

如果不能,请使用智能管理器(例如 std::unique_ptr)来为您处理内存清理。

无论如何,如果您手动调用delete您就做错了注意:不调用delete而让内存泄漏也是错误的

The simpler solution here is not to use int* in the first place.

#include <iostream>
#include <vector>


using namespace std;

typedef unsigned int uint;


class Foo {
    vector<int> coll; // remove *
public:

    void add(int item) { // remove *
       coll.push_back(item);
    }

    // remove ~Foo
};

int main()
{
   Foo foo;
   foo.add(4); // remove `new` call
   Foo bar = foo;

   return 0;
}

In general, try to avoid new.

If you cannot, use a smart manager (like std::unique_ptr) to handle the memory clean-up for you.

In any case, if you're calling delete manually, you're doing it wrong. Note: not calling delete and letting the memory leak is wrong too

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