2016-05-01 75 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; 
} 

編譯沒有警告(克++),執行沒有錯誤,並且由輸出判斷kill方法擦除從地圖foo對象。不過,我覺得這實際上可能是未定義的行爲。看起來在this之後的kill方法不再指向一個有效的對象。

C++標準對此有何評論?

+1

是的,它可以。 http://stackoverflow.com/questions/862093/object-delete-itself-from-container – Auriga

+1

基本上與['delete this;'](http://stackoverflow.com/q/3150942/2069064)相同的原理 – Barry

回答

7

當你進入你的killm[1](從m[1].kill(m, 1);)語句已充分評估爲你在調用killfoo對象。

然後你做m.erase(i);結束破壞當前對象foo

至於你使用當前對象(this)寫絕對沒有聲明,你從kill函數返回前,這是完全可以接受的,安全的(如由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; 
}; 

所以我們可以說,你在做什麼,如果你把它做好是有風險的,但有效的,安全的。

作爲一個例證,這最終會與定義的行爲,可以DONE:

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

有一個方法刪除當前對象可能不是一個好的做法呢(特別是如果另一個開發者後來修改了代碼...他可以很容易地使它與上面的第一個例子崩潰)。至少把一個明確的註釋在代碼中告訴當前對象可能已被銷燬(注意kill可能會破壞當前對象,一個又一個,或無...取決於m內容和i):

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

這根本不安全。 m.erase(i)將避免嘗試擦除多次調用同一對象,但如果多次調用m[1].kill(m, 1)是未定義的行爲。爲了更安全一些,m.at(1).kill(m, 1)將會拋出out_of_range錯誤。

+0

我的答案錯了,還是今天DV快樂的人? – user6279021

+0

@StoryTeller未定義的行爲是未定義的行爲。它說明'm [1]'不再有效。 – user6279021

+2

如果多次調用,它甚至不會有未定義的行爲...'m [1]'會首先插入一個新對象,該對象會立即被擦除。 – Barry

相關問題