2015-01-04 40 views
0

我有奇怪的斷言錯誤,我找不到這個代碼有什麼問題。C++斷言錯誤,同時刪除對象

斷言表達式是_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 

的想法是,一個對象女巫繼承者,可以創建任何其他對象,並保持指向的對象。程序員可以使用引用。當「超級」對象被銷燬時,所有「子」對象也被銷燬。

計劃得好好的,如果我更改爲:

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

現在創建方法(在這個例子中的物體A)只創建一個類型的對象。 但我需要,該創建方法可以創建任何繼承MyObject的對象。就像代碼的第一次和平一樣。

任何幫助這個斷言錯誤將不勝感激。謝謝。

+0

什麼是MyObject?它的析構函數是虛擬的嗎? –

+0

您在此處未顯示「MyObject」類。 – Ankur

+0

我不確定你可以在for循環中執行'item = 0;',但至少它沒用。 – wimh

回答

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>(); 
} 
+0

感謝您提供非常豐富的答案。 – Radon

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

謝謝,我感謝你的回答。 – Radon

0

問題是,你試圖刪除通過MyObject的指針對象,myObject的析構函數不是虛擬的。您可以使MyObject的析構函數爲虛擬,然後可以通過指向MyObject的指針刪除子類對象。有關此問題的更多詳細信息,請參閱this問題