1. ホーム
  2. c++

[解決済み] マップの要素をbeginからendまで繰り返しながらerase()を呼び出すとどうなるのでしょうか?

2022-07-03 02:58:27

質問

次のコードでは、マップをループして、ある要素を消去する必要があるかどうかをテストしています。 要素を消去して反復を続けることは安全ですか、それとも別のコンテナにキーを収集し、erase()を呼び出すために2番目のループを実行する必要がありますか?

map<string, SerialdMsg::SerialFunction_t>::iterator pm_it;
for (pm_it = port_map.begin(); pm_it != port_map.end(); pm_it++)
{
    if (pm_it->second == delete_this_id) {
        port_map.erase(pm_it->first);
    }
}

UPDATE: もちろん、私はその後 この質問を読む を読んだのですが、これは関係ないと思っていたのですが、私の質問に答えてくれています。

どのように解決するのですか?

C++11

これは C++11 で修正されました (または、消去が改善され、すべてのコンテナー タイプで一貫したものになりました)。

erase メソッドは、次のイテレーターを返すようになりました。

auto pm_it = port_map.begin();
while(pm_it != port_map.end())
{
    if (pm_it->second == delete_this_id)
    {
        pm_it = port_map.erase(pm_it);
    }
    else
    {
        ++pm_it;
    }
}

C++03

マップの要素を消しても、イテレータは無効にはなりません。

(削除された要素上のイテレータは別として)

実際に挿入または削除しても、どのイテレータも無効にはなりません。

この回答もご覧ください。

マーク・ランサム テクニック

しかし、コードを更新する必要があります。

あなたのコードでは、erase を呼び出した後に pm_it をインクリメントしています。この時点では手遅れで、すでに無効になっています。

map<string, SerialdMsg::SerialFunction_t>::iterator pm_it = port_map.begin();
while(pm_it != port_map.end())
{
    if (pm_it->second == delete_this_id)
    {
        port_map.erase(pm_it++);  // Use iterator.
                                  // Note the post increment.
                                  // Increments the iterator but returns the
                                  // original value for use by erase 
    }
    else
    {
        ++pm_it;           // Can use pre-increment in this case
                           // To make sure you have the efficient version
    }
}