更多 C++ 慣用法/Checked delete
提高delete表示式的安全性。
C++ 標準允許在 5.3.5/5 中,使用 delete-expression 刪除指向不完整類型別的指標。當類具有非平凡解構函式或類特定的 operator delete 時,行為是未定義的。一些編譯器在刪除不完整型別時會發出警告,但不幸的是,並非所有編譯器都會這樣做,並且程式設計師有時會忽略或停用警告。
在以下示例中,main.cpp 可以看到 Object 的定義。但是,main() 呼叫在 deleter.cpp 中定義的 delete_object(),它沒有看到 Object 的定義,而只是向前宣告它。對像這樣部分定義的型別呼叫 delete 是未定義的行為,一些編譯器不會標記它。
////////////////////
// File: deleter.hpp
////////////////////
// Declares but does not define Object.
struct Object;
void delete_object(Object* p);
////////////////////
// File: deleter.cpp
////////////////////
#include "deleter.hpp"
// Deletes an Object without knowing its definition.
void delete_object(Object* p)
{
delete p;
}
////////////////////
// File: object.hpp
////////////////////
struct Object
{
// This user-defined destructor won't be called when delete is
// called on a partially-defined (i.e., predeclared) Object.
~Object() {
// ...
}
};
////////////////////
// File: main.cpp
////////////////////
#include "deleter.hpp"
#include "object.hpp"
int main() {
Object* p = new Object;
delete_object(p);
}
Checked Delete 慣用法依賴於對函式模板的呼叫來刪除記憶體,該模板對於已宣告但未定義的型別將失敗,而不是對 delete 的呼叫。
以下是 Boost 效用庫中的函式模板 boost::checked_delete 的實現。它透過對引數化型別 T 呼叫 sizeof 運算子來強制編譯錯誤。如果 T 已宣告但未定義,sizeof(T) 將生成編譯錯誤或返回零,具體取決於編譯器。如果 sizeof(T) 返回零,checked_delete 透過宣告具有 -1 個元素的陣列來觸發編譯錯誤。陣列名稱是 type_must_be_complete,在這種情況下,它應該出現在錯誤訊息中,有助於解釋錯誤。
template<class T>
inline void checked_delete(T * x)
{
typedef char type_must_be_complete[ sizeof(T)? 1: -1 ];
(void) sizeof(type_must_be_complete);
delete x;
}
template<class T>
struct checked_deleter : std::unary_function <T *, void>
{
void operator()(T * x) const
{
boost::checked_delete(x);
}
};
注意:相同的技術也可以應用於陣列刪除運算子。
警告:std::auto_ptr 不使用任何等效於 checked delete 的東西。因此,如果在宣告 auto_ptr 時,模板引數型別未完全定義,則使用不完整型別例項化 auto_ptr 可能會導致其解構函式中的未定義行為。
- Boost 的 checked_delete。