web-dev-qa-db-ja.com

ループ内のunordered_mapから要素を消去する

StackOverflowにはいくつかの回答があり、次のループは、いくつかの述語predを満たすstd::unordered_mapから要素を消去するための優れた方法であることを示唆しています。

std::unordered_map<...> m;
auto it = m.begin();
while (it != m.end())
{
    if (pred(*it))
        it = m.erase(it);
    else
        ++it;
}

私は特にC++ 11(C++ 14ではなく)に興味があり、次の不吉な note on cppreference.com は、上記のループが未定義の動作に依存しており、動作しない可能性があることを示唆しています結局のところC++ 11:

消去されない要素の順序は保持されます(これにより、コンテナーを反復処理しながら個々の要素を消去できます)(C++ 14以降)

参照 タイトル2356。順序付けされていない連想コンテナでの消去の安定性 要求された表現の変更を含む Working Draft N3797 754ページの項目14( "で始まる追加フレーズ、および保存相対的な順序... ")。

この表現はN3797に関連しています。

[unord.req]、p14を次のように変更します。

-14- insertおよびemplaceメンバーは、コンテナー要素への参照の有効性に影響を与えませんが、コンテナーに対するすべてのイテレーターを無効にする場合があります。消去メンバーは、イテレータと消去された要素への参照のみを無効にし、消去されなかった要素の相対的な順序を保持します。

Cppreference.comからのメモの私の解釈が正しく、上記のループがC++ 11の未定義の動作に依存している場合、C++ 11でこの問題を解決する最も効率的な方法は何ですか?

22
foxcub

まあ、あなたはいつでもこれを行うことができます:

std::unordered_map<...> m;
std::vector<key_type> needs_removing;
for(auto&& pair : m)
{
    if (pred(pair))
        needs_removing.Push_back(pair.first);
}
for(auto&& key : needs_removing)
    m.erase(key);

遅いですが、複雑さは同じです。

1
Pubby