【问题标题】:C++ assertion error while deleting object删除对象时出现 C++ 断言错误
【发布时间】:2015-03-02 08:06:35
【问题描述】:

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

断言表达式是_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 的对象。就像在代码的第一次和平中一样。

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

【问题讨论】:

  • MyObject 是什么?它的析构函数是虚拟的吗?
  • 你没有在这里显示MyObject类。
  • 我不确定你是否可以在for循环中执行item = 0;,但至少它没有用。
  • MyObject 在这个例子中是一个空类。
  • @Wimmel:为什么不“允许”?不过确实没用。

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


【解决方案1】:

问题是您的 MyObject 类缺少虚拟析构函数,并且您尝试使用指向基类 MyObject 的指针对指向派生类的指针调用 delete。如果基类析构函数不是虚拟的,则通过基类指针在派生对象上发出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>();
} 

【讨论】:

    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

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

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

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

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

      【讨论】:

      • 谢谢,感谢您的回答。
      猜你喜欢
      • 2012-03-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多