map, lambda, remove_if



所以,我对std::map、lambda和stl算法(remove_if)有问题。实际上,和std::list或std::vector相同的代码也能很好地工作。

我的测试示例:

#include <map>
#include <iostream>
#include <algorithm>
struct Foo
{
    Foo() : _id(0) {}
    Foo(int id) : _id(id)
    {
    }
    int _id;    
};
typedef std::map<int, Foo> FooMap;

int main()
{
    FooMap m;
    for (int i = 0; i < 10; ++i)
        m[i + 100] = Foo(i);
    int removeId = 6;
    // <<< Error here >>>
    std::remove_if(m.begin(), m.end(), [=](const FooMap::value_type & item) { return item.second._id == removeId ;} ); 
    for (auto & item : m )
        std::cout << item.first << " = " << item.second._id << "n";    
    return 0;
}

错误消息:

In file included from /usr/include/c++/4.6/utility:71:0,
                 from /usr/include/c++/4.6/algorithm:61,
                 from main.cxx:1:
/usr/include/c++/4.6/bits/stl_pair.h: In member function ‘std::pair<_T1, _T2>& std::pair<_T1, _T2>::operator=(std::pair<_T1, _T2>&&) [with _T1 = const int, _T2 = Foo, std::pair<_T1, _T2> = std::pair<const int, Foo>]’:
/usr/include/c++/4.6/bits/stl_algo.h:1149:13:   instantiated from ‘_FIter std::remove_if(_FIter, _FIter, _Predicate) [with _FIter = std::_Rb_tree_iterator<std::pair<const int, Foo> >, _Predicate = main()::<lambda(const value_type&)>]’
main.cxx:33:114:   instantiated from here
/usr/include/c++/4.6/bits/stl_pair.h:156:2: error: assignment of read-only member ‘std::pair<const int, Foo>::first’

我不明白这里出了什么问题。因此,我很乐意阅读一些关于它的建议/说明。我的目标是使用新的lambda样式和std::map和算法,如remove_if。

g++4.6,-std=c++0x。

问题是std::map<K,V>::value_typestd::pair<const K, V>,也就是.firstconst,不可赋值。Lambdas与这里的问题无关。

std::remove_if通过移动容器的元素来"移除"项,这样所有不适合谓词的内容都在前面,在返回的迭代器之前。迭代器之后的所有内容都未指定。它通过简单的赋值来实现这一点,并且由于不能为const变量赋值,因此会出现错误

名称remove可能有点误导,在这种情况下,您确实想要erase_if,但遗憾的是,这并不存在。您将不得不对所有项目进行迭代,并用map.erase(iterator):手动擦除它们

for(auto it = map.begin(), ite = map.end(); it != ite;)
{
  if(it->second._id == remove_id)
    it = map.erase(it);
  else
    ++it;
}

这是安全的,因为您可以擦除树中的各个节点,而不会使其他迭代器无效。注意,我没有在for循环头中增加迭代器本身,因为在擦除节点的情况下,这会跳过元素。


†到目前为止,您应该已经注意到,这会对std::map的排序造成严重破坏,这就是为什么密钥是const的原因,因此在插入项目后,您不能以任何方式影响排序。

您可以对地图使用find和erase。它没有remove_if那么方便,但它可能是最好的。

int removeId = 6;
auto foundIter = m.find(removeId);
// if removeId is not found you will get an error when you try to erase m.end()
if(foundIter != m.end())
{
    m.erase(foundIter);
}

相关内容

  • 没有找到相关文章

最新更新