「SAFE_DELETE()系のdefineマクロ廃止」の編集履歴(バックアップ)一覧はこちら

SAFE_DELETE()系のdefineマクロ廃止」(2011/03/31 (木) 09:07:56) の最新版変更点

追加された行は緑色になります。

削除された行は赤色になります。

*SAFE_DELETE()系の#defineマクロ廃止 **なぜ#defineマクロを廃止するの? -const定数を使う理由と同じで、型が不鮮明であるため、なるべくC++では使わないほうがいいかと。 -マクロはプリプロセス実行なので型チェックが行われませんし、名前空間も存在しません。とても危険です。 **こういうの。 #ifndef SAFE_DELETE #define SAFE_DELETE(p) { if(p!=NULL) { delete (p); (p) = NULL; } } #endif #ifndef SAFE_DELETE_ARRAY #define SAFE_DELETE_ARRAY(p) { if(p!=NULL) { delete[] (p); (p) = NULL; } } #endif #ifndef SAFE_RELEASE #define SAFE_RELEASE(p) { if(p!=NULL) { (p)->Release(); (p) = NULL; } } #endif **じゃあどうするの? -templateを使います(キリッ **そもそも、なんでSAFE_DELETE()を使うの? -便利だから。 int main(){ int* unco = new int(4); //newで確保しちゃう。 std::cout << *unco << std::endl; delete (unco); //解放しちゃう。 unco = NULL; //危険だからNULLを入れる。 return 0; } -deleteで解放した後にuncoポインタが確保していた領域をさしてるのは危ないよね、ってことでNULLをいれる。 -だから、deleteしたあとわざわざNULLいれるの忘れがちだから、いっそのことSAFE_DELETEマクロ作っちゃおうぜ、的な。 -しかも、SAFE_DELETEなら、どんな型でもいけちゃうぜ!みたいな。だからみんな便利便利~って言って使ってるの。 **この場合のint型のSAFE_DELETE関数を実際に作っちゃおう。 void SafeDelete(int*& p) { if(p != NULL){ delete (p); (p) = NULL; } } int main(){ int* unco = new int(4); std::cout << *unco << std::endl; SafeDelete(unco); return 0; } -こんな感じかな?もし引数の「int型のポインタの参照」をみて吐き気がしたならきっとぼくと友達になれるかも。 -↓これでいいんじゃね?と思ってる人、 void SafeDelete(int* p) //p = 0x1b。代入! { if(p != NULL){ delete (p); //0x1bに確保されたint型のデータ(=156)をdelete (p) = NULL; //0x1bにNULLを入れる。←意味ない。本来なら0x3fにNULLをいれなきゃ。 } } int main(){ int* unco = new int(156); //uncoが指すアドレスは0x1b, unco自体のアドレスは0x3f SafeDelete(unco); //SafeDeleteに、「0x1b」を渡した return 0; } -これを動かすと、SafeDelete(unco)をしても、uncoにはNULLが入ってません。残念。 -なので、SafeDelete(int*&)のように、引数は「&bold(){ポインタの参照}」を使うのです。 -深く考えずに、こう考えるのが早い? void SafeDelete(int x) //これじゃだめ。(int& x)をパラメータにする { x = 0; } int main(){ int Number = 4; SafeDelete(Number); return 0; } -SafeDeleteを使って、Numberに0を入れたいんだけど、これどう考えても、0入らないよね。 -だから参照を使ったの。「"int"型」から「"int型のポインタ"型」に変わっただけ。 -っていうか、どうでもいいことかきまくりだね。 **で、これを元にSafeDelete関数をtemplateで書いちゃうだけ。 -「int」の部分をどんな型でもいけるようにtemplate使って書き変えちゃうだけ。 template <typename T> void SafeDelete(T*& p) { if(p != NULL){ delete (p); (p) = NULL; } } -ね、簡単でしょ? **そんでもってインライン関数化。 -#defineマクロと同じようになるべくプリプロセスあたりで展開してコードを置き換えてもらいたい願望。 -そこでインライン関数を使うことに。 -インライン関数なら、プリプロセスではないけどコンパイル時に展開してコードに置き換えられるからとても便利。 -短いコードじゃないとなかなかインライン化されないけど、これくらいならきっとコンパイラたんがなんとかしてくれるはず。 template <typename T> inline void SafeDelete(T*& p){ if(p != NULL) { delete (p); (p) = NULL; } } -これで#defineマクロと同じくらいパワフルな関数ができました。 -(なんか「パワフルな~」ってgems的な言い方だよね) **たぶん完成。はぴはぴはっぴー。 template <typename T> inline void SafeDelete(T*& p){ if(p != NULL) { delete (p); (p) = NULL; } } template <typename T> inline void SafeDeleteArray(T*& p){ if(p != NULL) { delete[] (p); (p) = NULL; } } template <typename T> inline void SafeRelease(T*& p){ if(p != NULL) { (p)->Release(); (p) = NULL; } } -もうこれを機に#defineマクロを使わないようにしようね。お兄さんとの約束。 **もう一度考察してみた -SAFE_DELETEマクロでは「if(p){}」とあるように、NULLポインタをdeleteしないようにしてある(のが一般的)。 --別にdelete演算子にNULLポインタ渡しちゃっていいんじゃない?無害でしょ? --delete演算子にNULLポインタを渡しても何も起きないのがC++の仕様らしいけど詳しくは知りませんの。 -ということでC++の標準規格に従ってみよう。 -ISO/IEC 14882の規格を見てみると 5.3.5 - Delete [expr.delete] 2 (中略)In either alternative, if the value of the operand of delete is the null pointer the operation has no effect. -とある。英語が不得意なことを忘れていたので改めて、JISX3014でこの項目を見てみると 5.3.5 delete式 2 (中略)いずれの形式であっても, deleteの演算対象の値が空のポインタの場合, その演算の効果はない. -とのこと。つまり、NULLポインタをdeleteしても何も起こりませんよ、と規格で保障されている。 -ということは、safe_deleteにはif(p != NULL)の処理はなくてもかまわないと思える。 -ただ、COMで使われる参照カウンタのReleaseの場合、話は別。あれはMSの方針に従うべき。 **備考 -templateを使うと、型の数だけ関数が作られて実行ファイルが大きくなっちゃうよね。 --オーベーヘッドになりかねないから、defineマクロのほうがよくない?って意見も考えられなくはない。 -必ずしも、inline関数がインライン化されるとは限らない。コンパイラによる。 -inline関数はちょっとした定義のものじゃないとインライン化されない。 -#defineマクロはプリプロセッサ命令、コンパイル前の段階で展開され置き換えがおきる。 -inline関数だと、コンパイル段階で展開され置き換えられる。 -NULL使ってる時点で#define廃止できてないよね。 --可読性のためにNULL使ってるだけで、実際は、0とかに置き換えたほうがいいかと思われ。 -SAFE_DELETE_ARRAY()みたく配列を解放するときの使い分けが面倒。 --<boost/array.hpp>を使えばおk。boost::shared_arrayとか便利よ。 --もしくはSTLとか。vectorさんなら配列みたく使えるぴょん。 -いっそスマートポインタ使えばよくない? --うん、エレガントなコードに期待してるよ。 **参考文献 [[MSDN - C/C++ Preprocessor Reference>http://msdn.microsoft.com/ja-jp/library/y4skk93w.aspx]](英語) -ISO/IEC 14882:1998 --[[http://www.kuzbass.ru:8086/docs/isocpp/]] - C++の規格書 -ISO/IEC 14882:2003 --日本工業規格JIS X 3014:2003 ---[[http://www.jisc.go.jp/]]でJIS番号"X3014"でデータベース検索 ---個人的な話、chromeだとうまく表示ができなかった。IEだとうまく見れた。
*SAFE_DELETE()系の#defineマクロ廃止 **なぜ#defineマクロを廃止するの? -const定数を使う理由と同じで、型が不鮮明であるため、なるべくC++では使わないほうがいいかと。 -マクロはプリプロセス実行なので型チェックが行われませんし、名前空間も存在しません。とても危険です。 **こういうの。 #ifndef SAFE_DELETE #define SAFE_DELETE(p) { if(p!=NULL) { delete (p); (p) = NULL; } } #endif #ifndef SAFE_DELETE_ARRAY #define SAFE_DELETE_ARRAY(p) { if(p!=NULL) { delete[] (p); (p) = NULL; } } #endif #ifndef SAFE_RELEASE #define SAFE_RELEASE(p) { if(p!=NULL) { (p)->Release(); (p) = NULL; } } #endif **じゃあどうするの? -templateを使います(キリッ **そもそも、なんでSAFE_DELETE()を使うの? -便利だから。 int main(){ int* unco = new int(4); //newで確保しちゃう。 std::cout << *unco << std::endl; delete (unco); //解放しちゃう。 unco = NULL; //危険だからNULLを入れる。 return 0; } -deleteで解放した後にuncoポインタが確保していた領域をさしてるのは危ないよね、ってことでNULLをいれる。 -だから、deleteしたあとわざわざNULLいれるの忘れがちだから、いっそのことSAFE_DELETEマクロ作っちゃおうぜ、的な。 -しかも、SAFE_DELETEなら、どんな型でもいけちゃうぜ!みたいな。だからみんな便利便利~って言って使ってるの。 **この場合のint型のSAFE_DELETE関数を実際に作っちゃおう。 void SafeDelete(int*& p) { if(p != NULL){ delete (p); (p) = NULL; } } int main(){ int* unco = new int(4); std::cout << *unco << std::endl; SafeDelete(unco); return 0; } -こんな感じかな?もし引数の「int型のポインタの参照」をみて吐き気がしたならきっとぼくと友達になれるかも。 -↓これでいいんじゃね?と思ってる人、 void SafeDelete(int* p) //p = 0x1b。代入! { if(p != NULL){ delete (p); //0x1bに確保されたint型のデータ(=156)をdelete (p) = NULL; //0x1bにNULLを入れる。←意味ない。本来なら0x3fにNULLをいれなきゃ。 } } int main(){ int* unco = new int(156); //uncoが指すアドレスは0x1b, unco自体のアドレスは0x3f SafeDelete(unco); //SafeDeleteに、「0x1b」を渡した return 0; } -これを動かすと、SafeDelete(unco)をしても、uncoにはNULLが入ってません。残念。 -なので、SafeDelete(int*&)のように、引数は「&bold(){ポインタの参照}」を使うのです。 -深く考えずに、こう考えるのが早い? void SafeDelete(int x) //これじゃだめ。(int& x)をパラメータにする { x = 0; } int main(){ int Number = 4; SafeDelete(Number); return 0; } -SafeDeleteを使って、Numberに0を入れたいんだけど、これどう考えても、0入らないよね。 -だから参照を使ったの。「"int"型」から「"int型のポインタ"型」に変わっただけ。 -っていうか、どうでもいいことかきまくりだね。 **で、これを元にSafeDelete関数をtemplateで書いちゃうだけ。 -「int」の部分をどんな型でもいけるようにtemplate使って書き変えちゃうだけ。 template <typename T> void SafeDelete(T*& p) { if(p != NULL){ delete (p); (p) = NULL; } } -ね、簡単でしょ? **そんでもってインライン関数化。 -#defineマクロと同じようになるべくプリプロセスあたりで展開してコードを置き換えてもらいたい願望。 -そこでインライン関数を使うことに。 -インライン関数なら、プリプロセスではないけどコンパイル時に展開してコードに置き換えられるからとても便利。 -短いコードじゃないとなかなかインライン化されないけど、これくらいならきっとコンパイラたんがなんとかしてくれるはず。 template <typename T> inline void SafeDelete(T*& p){ if(p != NULL) { delete (p); (p) = NULL; } } -これで#defineマクロと同じくらいパワフルな関数ができました。 -(なんか「パワフルな~」ってgems的な言い方だよね) **たぶん完成。はぴはぴはっぴー。 template <typename T> inline void SafeDelete(T*& p){ if(p != NULL) { delete (p); (p) = NULL; } } template <typename T> inline void SafeDeleteArray(T*& p){ if(p != NULL) { delete[] (p); (p) = NULL; } } template <typename T> inline void SafeRelease(T*& p){ if(p != NULL) { (p)->Release(); (p) = NULL; } } -もうこれを機に#defineマクロを使わないようにしようね。お兄さんとの約束。 **もう一度考察してみた -SAFE_DELETEマクロでは「if(p){}」とあるように、NULLポインタをdeleteしないようにしてある(のが一般的)。 --別にdelete演算子にNULLポインタ渡しちゃっていいんじゃない?無害でしょ? --delete演算子にNULLポインタを渡しても何も起きないのがC++の仕様らしいけど詳しくは知りませんの。 -ということでC++の標準規格に従ってみよう。 -ISO/IEC 14882の規格を見てみると 5.3.5 - Delete [expr.delete] 2 (中略)In either alternative, if the value of the operand of delete is the null pointer the operation has no effect. -とある。英語が不得意なことを忘れていたので改めて、JISX3014でこの項目を見てみると 5.3.5 delete式 2 (中略)いずれの形式であっても, deleteの演算対象の値が空のポインタの場合, その演算の効果はない. -とのこと。つまり、NULLポインタをdeleteしても何も起こりませんよ、と規格で保障されている。 -ということは、safe_deleteにはif(p != NULL)の処理はなくてもかまわないと思える。 -ただ、COMで使われる参照カウンタのReleaseの場合、話は別。あれはMSの方針に従うべき。 **備考 -templateを使うと、型の数だけ関数が作られて実行ファイルが大きくなっちゃうよね。 --オーベーヘッドになりかねないから、defineマクロのほうがよくない?って意見も考えられなくはない。 -必ずしも、inline関数がインライン化されるとは限らない。コンパイラによる。 -inline関数はちょっとした定義のものじゃないとインライン化されない。 -#defineマクロはプリプロセッサ命令、コンパイル前の段階で展開され置き換えがおきる。 -inline関数だと、コンパイル段階で展開され置き換えられる。 -NULL使ってる時点で#define廃止できてないよね。 --可読性のためにNULL使ってるだけで、実際は、0とかに置き換えたほうがいいかと思われ。 -SAFE_DELETE_ARRAY()みたく配列を解放するときの使い分けが面倒。 --<boost/array.hpp>を使えばおk。boost::shared_arrayとか便利よ。 --もしくはSTLとか。vectorさんなら配列みたく使えるぴょん。 -いっそスマートポインタ使えばよくない? --うん、エレガントなコードに期待してるよ。 **参考文献 -[[MSDN - C/C++ Preprocessor Reference>http://msdn.microsoft.com/ja-jp/library/y4skk93w.aspx]](英語) -ISO/IEC 14882:1998 --[[http://www.kuzbass.ru:8086/docs/isocpp/]] - C++の規格書 -ISO/IEC 14882:2003 --日本工業規格JIS X 3014:2003 ---[[http://www.jisc.go.jp/]]でJIS番号"X3014"でデータベース検索 ---個人的な話、chromeだとうまく表示ができなかった。IEだとうまく見れた。

表示オプション

横に並べて表示:
変化行の前後のみ表示:
記事メニュー
目安箱バナー