C++ 从循环中的无序映射中删除元素

C++ 从循环中的无序映射中删除元素,c++,c++11,unordered-map,C++,C++11,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; } std::无序映射m; 自动it=m.begin(); 而

关于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;
}
std::无序映射m;
自动it=m.begin();
而(it!=m.end())
{
if(pred(*it))
it=m.擦除(it);
其他的
++它;
}
我对C++11(与C++14相反)特别感兴趣,下面的不祥信息表明,上述循环依赖于未定义的行为,可能在C++11中根本不起作用:

未擦除的元素的顺序将被保留(这使得可以在遍历容器时擦除单个元素)(自C++14以来)

另请参见第754页第14项(附加短语开头“并保留相对顺序…”)的措辞变更请求

此措辞与N3797相关

修改[unord.req],第14页,如图所示:

-14-insert和emplace成员不应影响容器元素引用的有效性,但可能会使容器元素的所有迭代器无效 集装箱。擦除成员只能使迭代器和 引用已擦除的元素,并保留 未擦除的元素


如果我对cppreference.com中的注释的解释是正确的,并且上面的循环依赖于C++11中未定义的行为,那么在C++11中解决此问题的最有效方法是什么?

始终首先查阅stl算法

这一条似乎是通缉犯:

有关概述:

编辑 cppreference在站点底部有一个类似的示例。
它与c++11编译器配合使用。

好的,您可以随时这样做:

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);
std::无序映射m;
std::向量需要去除;
用于(自动和配对:m)
{
if(pred(对))
需要移除。向后推(成对,第一);
}
用于(自动和按键:需要删除)
m、 擦除(键);

速度较慢,但复杂度相同。

为了遵守C++11,很遗憾,您在如何处理这一问题上受到了一些限制。您的选择基本上可以归结为:

  • 迭代
    无序的\u映射
    ,建立一个要删除的键列表,如下所示:

    //std::unordered_map<...> mymap;
    std::vector<decltype(mymap)::key_type> vec;
    for (auto&& i : mymap)
        if (/*compare i*/)
            vec.emplace_back(i.first);
    for (auto&& key : vec)
        mymap.erase(key);
    

  • 如果(c++20)而不是循环,则使用擦除(请参阅)

    从地图中删除奇数关键点的示例:

    std::unordered_map<int, char> data {{1, 'a'},{2, 'b'},{3, 'c'},{4, 'd'},
                                        {5, 'e'},{4, 'f'},{5, 'g'},{5, 'g'}};
    
    const auto count = std::erase_if(data, [](const auto& item) {
        auto const& [key, value] = item;
        return (key & 1) == 1;
    });
    
    无序地图数据{{1,'a'},{2,'b'},{3,'c'},{4,'d'}, {5,'e'},{4,'f'},{5,'g'},{5,'g'}; 常量自动计数=标准::擦除_if(数据,[](常量自动和项目){ 自动常数&[key,value]=项; 返回(键&1)==1; });
    这不适用于任何关联容器。类似于什么?哪一个例子适用于C++11编译器?或者更确切地说,您如何知道它适用于C++11编译器?编译器不是隐式地使用C++14模式吗?您可以选择编译器版本,并且在本文中是标准的。我想这些信息是正确的。它使用GCC-4.8,一个只有C++11@jonas_toth从您链接的std::remove_if页面:
    这些算法不能与std::set和std::map等关联容器一起使用,因为它不取消对可移动可分配类型的引用(这些容器中的键不可修改)
    。通常,当约束像这样被加强时,这是因为由委员会成员代表的所有编撰者都已经一致了。你紧张是对的。@markransem有安全的方法吗?也就是说,在C++11标准下,正确的方法是什么?我怀疑没有一种方法可以保证安全,因此对标准进行了更改。找到了链接,这澄清了所有编译器的一致性。难道你不能重复使用
    mymap.begin()
    在循环中,并在它不是
    mymap.end()时将其删除。
    ?当然。我想我是想看看是否有更有效的解决方案。是的,1和3是我想到的两个选择。显然,我不喜欢其中任何一个,但我想不出比这更好的了。需要C++14编译吗?;)也许三年后。;-)
    //std::unordered_map<...> mymap;
    decltype(mymap) newmap;
    for (auto&& i : mymap)
        if (/*i is an element we want*/)
            newmap.emplace(std::move(i));
    mymap.swap(newmap);
    
    std::unordered_map<int, char> data {{1, 'a'},{2, 'b'},{3, 'c'},{4, 'd'},
                                        {5, 'e'},{4, 'f'},{5, 'g'},{5, 'g'}};
    
    const auto count = std::erase_if(data, [](const auto& item) {
        auto const& [key, value] = item;
        return (key & 1) == 1;
    });