web-dev-qa-db-ja.com

std :: list :: removeメソッドは、削除された各要素のデストラクタを呼び出しますか?

私はコードを持っています:

std::list<Node *> lst;
//....
Node * node = /* get from somewhere pointer on my node */;
lst.remove(node);

std::list::removeメソッドは、削除された各要素のデストラクタ(および空きメモリ)を呼び出しますか?もしそうなら、どうすればそれを避けることができますか?

27

はい、コンテナから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>を使用します。

45
fredoverflow

list内の各アイテムのデストラクタを呼び出しますが、これはNodeオブジェクトではありません。それは Node*

したがって、Nodeポインタは削除されません。

それは理にかなっていますか?

12
John Dibling

リスト内のデータのデストラクタを呼び出します。つまり、std::list<T>::removeTのデストラクタを呼び出します(これは、Tstd::vectorのようなものである場合に必要です)。

あなたの場合、それはNode*のデストラクタを呼び出しますが、これは何もしません。 nodeのデストラクタは呼び出されません。

7
jpalecek

はい。ただし、この場合、Node *にはデストラクタがありません。ただし、その内部に応じて、さまざまなNode *値は、スコープルールによって削除または破棄されます。いくつかの非基本的なタイプのノード*の場合、デストラクタが呼び出されます。

デストラクタはノードで呼び出されますか?いいえ。ただし、「ノード」はリストの要素タイプではありません。

あなたの他の質問に関しては、あなたはできません。標準リストコンテナ(実際にはすべての標準コンテナ)は、コンテンツの所有権を採用し、コンテンツをクリーンアップします。これを望まない場合は、標準のコンテナは適切な選択ではありません。

3
Edward Strange

ポインタをstd::listに配置しているため、ポイントされたNodeオブジェクトに対してデストラクタは呼び出されません。

ヒープに割り当てられたオブジェクトをSTLコンテナに格納し、削除時に破棄する場合は、boost::shared_ptrのようなスマートポインタでラップします。

0
wkl