Visual Studio 2010 C++运行时错误

4
我在使用Visual Studio 2010 C++编译器时遇到了奇怪的行为。 以下代码可以编译,但在执行后会抛出“Debug assertion failed”的错误信息:
"_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;
}

1
该错误是由VS调试运行时抛出的;如果您编译它为发布版本,则不会出现错误,但您可能会冒着崩溃的风险。如果您所说的GCC是指Linux上的GCC,则可以通过在valgrind下运行代码来看到相同的错误。 - Rup
4个回答

7
您没有实现复制构造函数和赋值运算符(请参阅三法则)。这将导致您的向量中的指针进行浅拷贝,导致双重删除和断言。编辑:双重删除是未定义行为,因此VS和gcc都是正确的,它们可以做任何它们想做的事情。
通常,在实现具有非平凡行为的析构函数时,您还需要编写或禁用复制构造和复制赋值。
然而,在您的情况下,您真的需要通过指针存储项目吗?如果不需要,请仅按值存储它们,问题就会得到解决。否则,如果您确实需要指针,请使用 shared_ptr (来自您的编译器或boost),而不是原始指针,以避免需要编写自己的析构/复制方法。
编辑:关于您的接口的进一步说明:像这样传递传入指针的接口可能会使使用您的类的人感到困惑。如果有人传递了未在堆上分配的int地址,则您的析构函数仍将失败。最好的方法是尽可能接受值,或在 add 函数中克隆传入的项目,使您自己调用 new

我不会盲目地推荐 shared_ptr,它们的行为很复杂(强引用/弱引用),因此在可以使用其他解决方案时最好避免使用。在这里,我认为 std::vector<int>std::vector< std::unique_ptr<int> >boost::ptr_vector<int> 是更优秀的选择。 - Matthieu M.

3
你重复删除了物品,因为这一行代码。
Foo bar = foo;

调用默认的复制构造函数,它会复制项目指针,而不是分配和复制数据。


2
问题在于barfoo成员的向量元素相同。当foo超出作用域时,它的析构函数被调用,释放指针并留下悬空的bar向量元素。bar析构函数尝试释放其悬空的向量元素,导致运行时错误。您应该编写一个复制构造函数。
Foo bar = foo; // Invokes default copy constructor.

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

请注意,这里的“三大法则”是指Rule of three

0

这里更简单的解决方案是一开始就不使用 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并让内存泄漏也是错误的

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接