メモリを割り当てるクラスがあるとします (今のところスマート ポインタについては忘れてください)。
class Foo
{
public:
Foo() : bar(new Bar)
{
}
~Foo()
{
delete bar;
}
void doSomething()
{
bar->doSomething();
}
private:
Bar* bar;
};
デストラクタ内のオブジェクトを削除するだけでなく、それらを NULL に設定する価値はありますか?
上記の例のデストラクタでポインタを NULL に設定するのは時間の無駄だと思います。
ベストアンサー1
いくつかの回答では、デバッグを支援するために DEBUG ビルドでこれを行う価値があるかもしれないと述べています。
こんなことしないで。
実際に顧客に提供するリリース ビルドでは隠されていない問題が、デバッグ ビルドでは隠される可能性があります (これは、デバッグ ビルドが持つべき効果とは逆の効果です)。
dtorのポインタを「クリア」する場合は、別のイディオムの方が良いでしょう。ポインタを既知の不正なポインタ値そうすれば、どこかにオブジェクトへの参照がぶら下がっていて、最終的にポインターを使用しようとする場合、バグのあるコードがポインターが NULL であることに気付いてポインターの使用を避けるのではなく、診断可能なクラッシュが発生します。
たとえば次doSomething()
のようになります:
void doSomething()
{
if (bar) bar->doSomething();
}
次に、を呼び出すbar
削除されたオブジェクトへの参照が残っている場合に、 を NULL に設定するとバグを隠すことができます。Foo
Foo::doSomething()
ポインタのクリーンアップが次のようになっている場合:
~Foo()
{
delete bar;
if (DEBUG) bar = (bar_type*)(long_ptr)(0xDEADBEEF);
}
バグを捕まえる可能性が高くなるかもしれません (ただし、放っておいてもbar
おそらく同様の効果があります)。
Foo
これで、削除されたオブジェクトへの未解決の参照が何かにある場合、bar
を使用すると NULL チェックによりその参照が回避されなくなります。ポインターを使用しようとするためクラッシュが発生し、デバッグ ビルドでは何も問題が起きませんが、顧客のリリース ビルドでは未解決の参照が (悪影響で) 引き続き使用されることになります。このクラッシュは修正可能です。
デバッグ モードでコンパイルする場合、デバッグ ヒープ マネージャーが既にこの処理を実行している可能性がかなり高くなります (少なくとも MSVC のデバッグ ランタイム ヒープ マネージャーは、解放されたメモリを 0xDD で上書きして、メモリが使用されていない/解放されていることを示します)。
重要なのは、生のポインターをクラス メンバーとして使用している場合、dtor の実行時にポインターを NULL に設定しないことです。
このルールは他の生のポインタにも適用される可能性がありますが、それはポインタがどのように使用されるかによって異なります。