簡體   English   中英

C++ 擦除映射中的鍵值,同時迭代它

[英]C++ Erase key-value in map while iterating over it

以下 C++ 代碼似乎有效,我很想了解如何:

    std::map<char,char> mymap;
    mymap['a'] = 'A'; mymap['b'] = 'B'; mymap['c'] = 'C';
    mymap['d'] = 'D'; mymap['e'] = 'E'; mymap['f'] = 'F';
    mymap['g'] = 'G'; mymap['h'] = 'H'; mymap['i'] = 'I';

    bool erase = true;
    for (auto& [key, value] : mymap) {
        if (erase) mymap.erase(key); // Erasing every other item!!
        erase = !erase;
    }

我在迭代時修改地圖。 來自 JVM 世界,我期待各種CuncurrentModificationException ......但它似乎在 C++ 中工作正常。

這真的打破了嗎,我只是走運了? 如果沒有,這在幕后如何工作?

大多數這樣做的例子都使用迭代器,我猜這是有原因的嗎? 這種方式對我來說看起來更干凈,我懷疑有人會在沒有充分理由的情況下for (auto& it = mymap::begin(); it != mymap::end; ) { it++ }選擇更冗長且不易辨認的方法。

C++ std使用窄契約來允許程序更快。

狹義合約是一種並非每個操作都有保證結果的合約。 如果您違反了合同條款,C++ 不保證您的程序的行為。

在這種情況下,您在使用引用它的迭代器進行迭代時銷毀元素。 這會使迭代器無效,並且for(;)循環中的隱式++ Advance 操作違反了您與std庫的合同。

有了一個寬合同,你會在這里得到一個例外。 使用弱合同,您會得到未定義的行為。 有時它“有效”,有時它崩潰,有時它會將您的瀏覽器歷史記錄通過電子郵件發送給您的祖母並刪除您的 Gmail 帳戶。

所有這些都是對違反合同的有效回應。 C++ 標准對可執行文件的功能沒有任何限制。 這可以包括時間旅行(不,這不是一個笑話;UB 允許編譯器在程序到達 UB 之前更改它在行上所做的事情)。

我個人曾經寫過一個remove_erase_if算法來解決這個問題。 是的,它使用迭代器。

如果您想刪除所有其他項目,您主要必須編寫類似的內容:

for (auto it = mymap.begin, itEnd = mymap.end(); it != itEnd; ++it)
{
    auto itTemp = it;
    ++it;
    mymap.erase(itTemp);
    if (it == itEnd)
    {
        break;
    }
}

也就是說,您必須制作迭代器的副本,以便在擦除項目后仍然可以擁有一個有效的迭代器。

請注意,上面的代碼對於map是正確的,但不適用於vector

這就是為什么每次執行可能會使迭代器、引用或指向項的指針(如果您不知道規則)無效的操作時都必須閱讀文檔的原因。

有關地圖,請參閱http://www.cplusplus.com/reference/map/map/erase/

更新

循環的前 3 行可以在 C++ 11 中替換為

it = mymap.erase(it);

因為 never 函數返回一個迭代器到下一個元素。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM