delete演算子とfree関数はNULLチェックは不要
delete演算子とfree関数は、NULLを渡した場合、何も処理が行われないことが保証されています。なので以下のようなコードは、
if ( p ) { delete p; }
このようにシンプルに書くことができます。
delete p;
malloc関数に対応するfree関数も同様です。
2重解放には注意が必要
delete演算子、free関数にNULLチェックは不要ですが、2重解放には注意が必要です。
class A { int* m_pInt; public: A() : m_pInt( 0 ){} void CreateInt( void ) { DeleteInt(); m_pInt = new int; } void DeleteInt( void ) { delete m_pInt; } }; int main() { A a; a.CreateInt(); a.DeleteInt(); a.CreateInt(); // <- ここで2重開放が発生 return 0; }
intを作成して、削除して、また作成しているプログラムですが、よくみると2重開放が発生しています。
プログラムの流れ
- a.CreateInt();
- DeleteInt();
- delete m_pInt; // m_pIntはNULLなので何も起こらない
- m_pInt = new int;
- DeleteInt();
- a.DeleteInt();
- delete m_pInt; // m_pInt 解放
- a.CreateInt();
- DeleteInt();
- delete m_pInt; // m_pInt また解放!?これは2重解放だ
- m_pInt = new int;
- DeleteInt();
何がいけなかったのかというと、delete m_pInt;
したあとにm_pInt
にNULLを入れて置かなかったことです。このような事態を避けるために、delete
後のポインタには必ずNULLを代入するようにします。
以下のようにマクロやtemplateで「deleteとNULLポインタのセット」をまとめた処理を作ってしまうのもいいかもしれません。
// マクロバージョン #define SAFE_DELETE( p ) delete p; p = 0 // templateバージョン template<class T> void SafeDelete( T*& p ) { delete p; p = 0; } int main() { { int* p_int = new int; SAFE_DELETE( p_int ); } { int* p_int = new int; SafeDelete( p_int ); } return 0; }