删除对象时出现 C++ 断言错误

C++ assertion error while deleting object

我有一个奇怪的断言错误,我找不到这段代码有什么问题。

断言表达式是_BLOCK_TYPE_IS_VALID(pHead->nBlockUse).

我稍微简化了代码以提高可读性。

class Creator
{
public:
    virtual ~Creator()
    {
        for (MyObject* item : _list)
        {
            delete item; <-- assertion error here
            item = 0;
        }
        _list.clear();
    }

    template <class T>
    T& create()
    {
        T * item = new T();
        _list.push_back(item);
        return *item;
    }

private:
    std::list<MyObject*> _list;
};

class A : public MyObject, public Creator
{
};

class B : public MyObject, public Creator
{
};

int main()
{
    A a;
    a.create<A>();
} <-- call of destructor

这个想法是一个对象继承了 Creator,可以创建任何其他对象,并保存指向这些对象的指针。虽然程序员可以使用引用。当 "super" 个对象被销毁时,所有 "sub" 个对象也被销毁。

如果我改为:

template <class T>
class Creator
{
public:
    virtual ~Creator()
    {
        for (T* item : _list)
        {
            delete item;
            item = 0;
        }
        _list.clear();
    }

    T& create()
    {
        T * item = new T();
        _list.push_back(item);
        return *item;
    }

private:
    std::list<T*> _list;
};

class A : public MyObject, public Creator<A>
{
};

class B : public MyObject, public Creator<B>
{
};

int main()
{
    A a;
    a.create();
}

现在 create 方法只创建一种类型的对象(本例中的对象 A)。 但我需要,该创建方法可以创建任何继承 MyObject 的对象。就像代码的第一个和平。

对于此断言错误的任何帮助将不胜感激。谢谢

我认为问题在于多重继承。下面是重现问题的简化方法。 可以通过

修复
  • 将其转换为派生程度最高的类型或
  • 让基础的析构函数 class 是虚拟的。

在您的情况下,虚函数方法是最好的,因为建议将基础 class 析构函数设为虚拟,以便通过继承层次结构进行析构调用。

class A 
{
};

class B
{
};

class C : public A, public B
{
};

int main()
{
    // Fails with memory heap error
    B* pB = new C();
    delete pB;
}

修复它

int main()
{
    B* pB = new C();
    // Casting it to the "full" type will fix it
    C* pC = static_cast<C*>(pB);
    delete pC;
}

第二个程序有效,因为它与下面的程序类似。

int main()
{
    // Pointer to the "full" type works
    C* pC = new C();
    delete pC;
}

问题是您的 MyObject class 缺少虚拟析构函数,并且您试图使用指向基类的指针在指向派生 class 的指针上调用 delete classMyObject。如果基 class 析构函数不是虚拟的,则通过基 class 指针在派生对象上发出 delete 是未定义的行为。

5.3.5 Delete (Paragraph 3)

In the first alternative (delete object), if the static type of the operand is different from its dynamic type, the static type shall be a base class of the operand’s dynamic type and the static type shall have a virtual destructor or the behavior is undefined.

一旦析构函数在基 class MyClass 中变为虚拟,以下在 Visual Studio 2013 中可以正常工作:

#include <list>
struct MyObject 
{
    virtual ~MyObject() {}
};

class Creator
{
public:
    virtual ~Creator()
    {
        for (MyObject* item : _list)
        {
            delete item; 
            item = 0;
        }
        _list.clear();
    }

    template <class T>
    T& create()
    {
        T * item = new T();
        _list.push_back(item);
        return *item;
    }

private:
    std::list<MyObject*> _list;
};

class A : public MyObject, public Creator
{
};

class B : public MyObject, public Creator
{
};

int main()
{
    A a;
    a.create<A>();
} 

问题是您尝试通过 MyObject 指针删除 A 对象,而 MyObject 析构函数不是虚拟的。您可以使 MyObject 的析构函数成为虚拟的,然后您可以通过指向 MyObject 的指针删除子类对象。有关此问题的更多详细信息,请参阅 this 问题