私はコードを持っています:
std::list<Node *> lst;
//....
Node * node = /* get from somewhere pointer on my node */;
lst.remove(node);
std::list::remove
メソッドは、削除された各要素のデストラクタ(および空きメモリ)を呼び出しますか?もしそうなら、どうすればそれを避けることができますか?
はい、コンテナからFoo*
を削除すると、Foo*
は破棄されますが、Foo
は解放されません。生のポインタを破壊することは常に何もしません。それ以外の方法はありません!いくつかの理由をお話ししましょう。
ポインターの削除は、ポインターが実際に動的に割り当てられた場合にのみ意味がありますが、ポインター変数が破棄された場合にランタイムがそれを知ることができるでしょうか。ポインターは静的変数と自動変数を指すこともでき、それらの1つを削除すると 未定義の動作 になります。
{
Foo x;
Foo* p = &x;
Foo* q = new Foo;
// Has *q been allocated dynamically?
// (The answer is YES, but the runtime doesn't know that.)
// Has *p been allocated dynamically?
// (The answer is NO, but the runtime doesn't know that.)
}
先の尖った人が過去にすでに解放されているかどうかを知る方法はありません。同じポインタを2回削除すると、 未定義の動作 になります。 (最初の削除後、ダングリングポインタになります。)
{
Foo* p = new Foo;
Foo* q = p;
// Has *q already been released?
// (The answer is NO, but the runtime doesn't know that.)
// (...suppose that pointees WOULD be automatically released...)
// Has *p already been released?
// (The answer WOULD now be YES, but the runtime doesn't know that.)
}
また、ポインタ変数が初期化されているかどうかを検出することもできません。そのようなポインタを削除しようとするとどうなると思いますか?繰り返しますが、答えは 未定義の振る舞い です。
{
Foo* p;
// Has p been properly initialized?
// (The answer is NO, but the runtime doesn't know that.)
}
型システムは、単一のオブジェクトへのポインター(Foo*
)とオブジェクトの配列の最初の要素へのポインター(これもFoo*
)を区別しません。ポインタ変数が破棄されると、ランタイムは、delete
またはdelete[]
のどちらを介してポインティを解放するかを判断できない可能性があります。間違った形式でリリースすると、 未定義の動作 が呼び出されます。
{
Foo* p = new Foo;
Foo* q = new Foo[100];
// What should I do, delete q or delete[] q?
// (The answer is delete[] q, but the runtime doesn't know that.)
// What should I do, delete p or delete[] p?
// (The answer is delete p, but the runtime doesn't know that.)
}
ランタイムはポインティに対して意味のあることを何もできないので、ポインタ変数を破棄することは常に何もしません。何もしないことは、情報に基づいていない推測のために未定義の動作を引き起こすよりも間違いなく優れています:-)
生のポインターの代わりに、コンテナーの値型としてスマートポインターを使用することを検討してください。これは、スマートポインターが、不要になったときにポインターを解放する責任があるためです。必要に応じて、std::shared_ptr<Foo>
またはstd::unique_ptr<Foo>
を使用します。コンパイラがまだC++ 0xをサポートしていない場合は、boost::shared_ptr<Foo>
を使用してください。
Never 、繰り返しますが、NEVER EVERは、コンテナの値型としてstd::auto_ptr<Foo>
を使用します。
list
内の各アイテムのデストラクタを呼び出しますが、これはNode
オブジェクトではありません。それは Node*
。
したがって、Node
ポインタは削除されません。
それは理にかなっていますか?
リスト内のデータのデストラクタを呼び出します。つまり、std::list<T>::remove
はT
のデストラクタを呼び出します(これは、T
がstd::vector
のようなものである場合に必要です)。
あなたの場合、それはNode*
のデストラクタを呼び出しますが、これは何もしません。 node
のデストラクタは呼び出されません。
はい。ただし、この場合、Node *にはデストラクタがありません。ただし、その内部に応じて、さまざまなNode *値は、スコープルールによって削除または破棄されます。いくつかの非基本的なタイプのノード*の場合、デストラクタが呼び出されます。
デストラクタはノードで呼び出されますか?いいえ。ただし、「ノード」はリストの要素タイプではありません。
あなたの他の質問に関しては、あなたはできません。標準リストコンテナ(実際にはすべての標準コンテナ)は、コンテンツの所有権を採用し、コンテンツをクリーンアップします。これを望まない場合は、標準のコンテナは適切な選択ではありません。
ポインタをstd::list
に配置しているため、ポイントされたNode
オブジェクトに対してデストラクタは呼び出されません。
ヒープに割り当てられたオブジェクトをSTLコンテナに格納し、削除時に破棄する場合は、boost::shared_ptr
のようなスマートポインタでラップします。