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

时间:2015-01-04 17:46:55

标签: c++ inheritance runtime-error assertion delete-operator

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

断言表达式为_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)。 但我需要,create方法可以创建任何继承MyObject的对象。就像在第一次和平代码中一样。

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

3 个答案:

答案 0 :(得分:1)

问题是您的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>();
} 

答案 1 :(得分:0)

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

修复
  • 将其转换为派生类型最多的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;
}

答案 2 :(得分:0)

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