天天看點

STL容器删除元素的陷阱

今天看Scott Meyers大師的stl的用法,看到了我前段時間犯的一個錯誤,發現我寫的代碼和他提到錯誤代碼幾乎一模一樣,有關stl容器删除元素的問題,錯誤的代碼如下:

std::vector<struct> mFriendList;

...

std::vector<struct>::iterator iter = mFriendList.begin();

for ( ; iter != mFriendList.end(); ++iter)

{

    if (...)

        mFriendList.erase(iter);

}

記得當時Once給我說過這個問題,還給我改過代碼,我當時不明白為什麼,隻知道程式執行的時候如果if為true那麼程式就肯定會崩潰。

大師的說法是:當容易中的一個元素被删除時,指向該元素的所有疊代器都變得無效。上面的代碼中,隻要執行了erase(iter),那麼iter就會變得無效,那麼執行++iter就肯定會出錯。

在網上看到有人總結如下兩條:

1. 對于節點式容器(map, list, set)元素的删除,插入操作會導緻指向該元素的疊代器失效,其他元素疊代器不受影響

2. 對于順序式容器(vector,string,deque)元素的删除、插入操作會導緻指向該元素以及後面的元素的疊代器失效

總結了一下,并回想Once當時給我改的代碼,是以正确的寫法應該是這樣的:

1.對于節點式容器

std::list<struct> mList;

std::list<struct>::iterator iter = mList.begin();

for ( ; iter != mList.end(); )

    {

        //因為節點式隻會導緻目前節點疊代器失效,是以删除節點的同時對疊代器進行後移的操作,因為其他元素不會失效

        mList.erase(iter++);

    }

    else

        ++iter;

2.對于順序式容器

std::vector<struct> mVector;

std::vector<struct>::iterator iter = mVector.begin();

for ( ; iter != mVector.end(); )

        //這裡就比較有說法了,因為順序式容器會使本身和後面的元素疊代器都失效,是以不能簡單的++操作

        //這裡順序式容器的erase()會傳回緊随被删除元素的下一個元素的有效疊代器

        //而節點式容器的erase()的傳回值是void,這點我感覺太神奇了,确實太神奇了!!!!

        iter = mVector.erase(iter);

注意:容器看具體STL庫的實作了,VS中兩類容器的earse都傳回下一個疊代器指針。

繼續閱讀