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

C++ assertion error while deleting object

本文关键字:断言 错误 C++ 对象 删除      更新时间:2023-10-16

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

断言表达式为 _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,可以创建任何其他对象,并持有指向这些对象的指针。而程序员可以使用引用。当"超级"对象被销毁时,所有"子"对象也会被销毁。

如果我更改为:

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的任何对象。就像在代码的第一次和平中一样。

对此

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

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

5.3.5 删去(第3款)

在第一个备选方案(删除对象)中,如果静态类型 操作数与其动态类型不同,静态类型应为操作数的动态类型的基类,静态类型应具有虚拟析构函数或行为未定义

一旦析构函数在基类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 指针删除对象,并且 MyObject 析构函数不是虚拟的。你可以使MyObject的析构函数成为虚拟的,然后你可以通过指向MyObject的指针删除子类对象。有关此问题的更多详细信息,请参阅此问题

我认为问题出在多重继承上。下面是重现问题的简化方法。它可以通过以下方式修复

  • 将其强制转换为派生最多的类型 OR
  • 使基类的析构函数是虚拟的。

在您的情况下,虚函数方法是最好的,因为建议将基类析构函数设置为虚拟,以便通过继承层次结构获取销毁调用。

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;
}