2016-05-01 8 views
11

オブジェクトは標準のC++コンテナから自身を消去できますか?

#include <iostream> 
#include <map> 

struct foo 
{ 
    void kill(std::map<int, foo>& m, int i) 
    { 
    m.erase(i); 
    } 
}; 

int main() 
{ 
    std::map<int, foo> m; 

    m.emplace(1, foo()); 

    std::cout << m.size() << std::endl; 

    m[1].kill(m, 1); 

    std::cout << m.size() << std::endl; 
} 

は(G ++)を警告なしでコンパイル次のコードは、エラーなしで実行され、出力によって判定kill方法は、マップからfooオブジェクトを消去します。しかし、これは実際には未定義の動作かもしれないと私は感じている。 killメソッドの後に、m.erase(i)thisは、もはや有効なオブジェクトを指していないようです。

これについてC++標準では何と言いますか?

+1

はいできます。 http://stackoverflow.com/questions/862093/object-delete-itself-from-container – Auriga

+1

['delete this;']と基本的に同じ原則(http://stackoverflow.com/q/3150942/2069064) – Barry

答えて

7

あなたkillを入力すると、m[1]m[1].kill(m, 1);から)文は完全にあなたがkillを上呼びかけているfooオブジェクトであると評価されています。

次に、m.erase(i);は、現在のオブジェクトfooを破棄して終了します。

は限りあなたがkill関数から戻る前に、現在のオブジェクト(this)を使用して、絶対にない文を書かないと、それは(AurigaBarryによって参照記事でコメントしたように)完全に受け入れられると安全です。現在のオブジェクトがもはや存在しなくても、関数はスタックから安全に返されます。私が知る限り、失敗する理由はありません。実例として

、これは未定義の動作で終わるだろうとしてはいけない:

struct foo 
{ 
    void kill(std::map<int, foo>& m, int i) 
    { 
    m.erase(i); 
    cout << attribute; // don't do that! current foo object does not exist anymore 
    } 
    int attribute; 
}; 

それでは、あなたもそれを行うならば何をやっていることは危険ではなく、有効かつ安全であるとしましょう。

例示として、これは定義された動作で終わるであろうと行うことができる:

struct foo 
{ 
    void kill(std::map<int, foo>& m, int i) 
    { 
    int theAttribute = attribute; 
    m.erase(i); 
    cout << theAttribute; // OK! 
    } 
    int attribute; 
}; 

メソッドが現在のオブジェクトを削除したが、とにかく(別の開発者がコードを後で変更し特別場合、おそらく良い方法ではありません...彼は簡単に上記の最初の例でクラッシュすることができます)。

struct foo 
{ 
    void kill(std::map<int, foo>& m, int i) 
    { 
    m.erase(i); 
    // careful! current object could have been destroyed by above statement and may not be valid anymore! Don't use it anymore! 
    } 
}; 
-4
:少なくとも現在のオブジェクトが破壊されている可能性が伝えるために、コードで明示的なコメントを(別の1、またはnone ... m内容と iに応じて、 killは、現在のオブジェクトを破壊する可能性があることに注意してください)置きます

これはまったく安全ではありません。 m.erase(i)複数回呼び出された場合、同じオブジェクトを消去しようとすることはありませんが、複数回呼び出すとm[1].kill(m, 1)は未定義の動作になります。わずかに安全になるように、m.at(1).kill(m, 1)out_of_rangeというエラーをスローします。

+0

Is私の答えは間違っているのですか? – user6279021

+0

@StoryTeller未定義の動作は未定義の動作です。 'm [1]'はもはや有効ではないことを示しています。 – user6279021

+2

複数回呼び出された場合でも未定義の動作ではありません。 'm [1]'は最初に新しいオブジェクトを挿入し、直ちに消去されます。 – Barry

関連する問題