erase方法是否影響其它iterator?

來源:互聯網
上載者:User

有時候會有這麼一種不太常見的需求:從一個map中刪除所有符合某種條件的項目,而這種條件與map的key基本沒啥關係。

比如,一個儲存學生花名冊的map,key為學號(int),value為姓名(string),如果要按學號刪除很容易,但如果需要刪除該map中所有姓“張”的學生,就只能遍曆它,逐一比較了。

using namespace std;<br />typedef map<int, string> MAP;<br />static bool canDrop(const MAP::value_type & v) {<br /> return 0 == strncmp(v.second.c_str(), "張", 2);<br />}

下面是顯而易見的錯誤方法

// 第一種方法(錯誤的方法)!!<br />for (MAP::iterator it = theMap.begin(); theMap.end()!=it; ++it) {<br /> if (canDrop(*it)) {<br /> // 錯誤:當erase執行以後,it立刻就失效了,在執行到for迴圈的++it時就會出現未知後果。<br /> theMap.erase(it);<br /> }<br /> }

如果用的是VC編譯器,由於它對erase方法的擴充,所以用下面的方法,可以正確完成需求:

// 第2種方法,僅適用於VC<br />for (MAP::iterator it = theMap.begin(); theMap.end()!=it;) {<br /> if (canDrop(*it)) {<br /> // VC擴充了erase方法,使它返回下一個合法的迭代器<br /> it = theMap.erase(it);<br /> } else {<br /> ++ it;<br /> }<br />}

可惜,C++標準中的map::erase()方法並不返回任何值,所以上述代碼在g++等編譯器中無法通過編譯。為了符合標準,下面有一種安全的方法——即將不需要刪除的項Copy到另一個新的容器裡,然後交換兩個容器的內容。

// 第3種方法,適用任何編譯器,但有額外開銷<br />MAP tmp; // 臨時容器<br />for (MAP::iterator it = theMap.begin(); theMap.end()!=it; ++it) {<br /> if (!canDrop(*it)) {<br /> // 複製不需要刪除的薦到臨時容器<br /> tmp.insert(*it);<br /> }<br />}<br />theMap.swap(tmp); // 交換兩個容器的內部,此時 theMap 中包含正確的項

這種“複製不需要刪除項到臨時容器”的方法符合C++標準,也很容易理解,但如果不需要刪除的項目數很多時(或者MAP的值拷貝開銷很大時),就不太適合了。下面是另一種方法:

// 第4種方法<br />for (MAP::iterator it = theMap.begin(); theMap.end()!=it;) {<br /> if (canDrop(*it)) {<br /> // 在erase之前,先遞增迭代器,此時由於erase尚未被調用,所以遞增後的迭代器有效<br /> // 然後用迭代器的原始值來調用erase,確何刪除正確的薦<br /> theMap.erase(it++);<br /> } else {<br /> ++it;<br /> }<br />}

上例中,it++這個操作,首先儲存了it的原始值,然後對it進行自增操作,由於此時erase尚未被調用,所以it的原始值有效,自增後的it也是有效;然後,將it的原始值傳遞給erase()方法,正確地刪掉項目。

現在的問題是,map的erase操作,除了影響被刪除項目的iterator(使指向這個項目的iterator變成無效),還會影響其它iterator嗎?比如說,下面這種方法來完成需求:

// 第5種方法<br />vector<MAP::iterator> itList;<br />// 儲存所有要刪除項目的iterator到臨時容器<br />for (MAP::iterator it=theMap.begin(); theMap.end() != it; ++it) {<br /> if (canDrop(*it)) {<br /> itList.push_back(it);<br /> }<br />}<br />// 遍曆臨時容器,取出裡面的iterator,逐一刪除<br />for (vector<MAP::iterator>::iterator it2 = itList.begin(); itList.end() != it2; ++it2) {<br /> theMap.erase( *it2 );<br />}

從測試結果來看,那些儲存在臨時容器裡的iterator,並不因為其它iterator的失效而失效。

不過,這是C++標準嗎?如果標準的確規定了erase並不影響其它iterator,那麼第四種方法顯然是最好的……可惜我查了半天沒查到。有知道的達人不妨告訴我一聲,謝謝。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.