2015-03-31 73 views
3

簡而言之:刪除模板化指針不會調用析構函數。C++:不使用嵌入模板調用的析構函數

包括解決問題。爲什麼?

我剛碰到一個我無法解釋的情況。我試圖在這裏打破更復雜的情況。

文件R.cpp

class R { 
     Owner<Problem> m_o; 
     void cleanUp() { m_o.clear(); } 
    } 

文件Owner.cpp

struct DeleteFunctor { 
    template< class TPtr > void operator()(TPtr* ptr) { delete ptr; } 
}; 

template< class T > 
class Owner { 
std::vector<T*> m_objects; 
// here add and other stuff 
void clear() { 
    std::for_each(m_objects.begin(), m_objects.end(), DeleteFunctor()); 
    m_objects.clear(); 
} 

我現在有堆上創建新問題的對象,並將它們直接插入到m_o一個實用程序類。我知道將引用導出到內部類型是不好的方式,但這不是重點。

如果我打電話給cleanUp(),我可以追蹤到Functor的調用delete ptr,ptr的問題類型正確。但問題 - 析構函數不叫!

但是,包括文件R.cpp中的問題標題可以修復問題。該comiler不抱怨。這是一個編譯器錯誤?

系統: 克++(Ubuntu的4.8.2-19ubuntu1)4.8.2

+1

爲什麼不'std :: vector >'? – 2015-03-31 10:27:29

+0

在這種情況下可能會發生什麼? – Robinson 2015-03-31 10:27:38

+0

添加或刪除這樣的代碼行然後看到不同的行爲表明您有內存損壞錯誤。你真正要做的就是改變可執行映像,將錯誤轉移到程序的不同部分。所以你真的沒有解決這個問題。 – PaulMcKenzie 2015-03-31 10:31:02

回答

4

從標準(草案n3242)§5.3.5/ 5:

如果對象被刪除具有不完整的在刪除點處的類類型和完整的類具有非平凡的析構函數或解除分配函數時,行爲是未定義的。

如果不包括在這種情況下定義TProblem頭,那麼你刪除不完全類型的對象。如果該類型不滿足該條款中的要求,那麼刪除具有未定義的行爲。

這是一個編譯器錯誤嗎?

不,編譯器不需要警告未定義的行爲。

您可能希望要求TOwner是完整的。如果T不完整,則static_assert(sizeof(T) > 0)之類的內容應該無法編譯。

如果你不能依賴當前的標準,你可以改用boost::checked_deleter作爲你的刪除函子。它在pre ++ 11中完成完整性檢查。如果你出於某種原因不想包含boost頭文件,那麼只需重新實現它。這是檢查完整性的代碼。

// intentionally complex - simplification causes regressions 
typedef char type_must_be_complete[ sizeof(T)? 1: -1 ]; 
(void) sizeof(type_must_be_complete); 
delete x; 

請注意,您有效地是部分重新實現std::vector<std::unique_ptr<T>>如果你可以使用C++ 11,我建議使用來代替。

+0

這在標準中出現在哪裏?你可以編輯? – UmNyobe 2015-03-31 10:34:15

+0

@UmNyobe編輯。 – user2079303 2015-03-31 10:37:35

+0

當然這是有道理的 - 如果你給我看一塊內存並說「在這裏刪除foobar」,除非我知道foobar有多大才知道我在做什麼。 – OJFord 2015-03-31 10:48:26