所以,我对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’
我不明白这里有什么问题。所以,我很乐意阅读有关它的一些建议/指示。我的目标 - 使用带有std :: map和算法的新lambda样式,例如remove_if。
g ++ 4.6,-std = c ++ 0x。
答案 0 :(得分:28)
问题是std::map<K,V>::value_type
为std::pair<const K, V>
,又名.first
为const
且无法转让。 Lambda与这里的问题无关。
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
的原因 - 因此您无法影响排序插入项目后的任何方式。
答案 1 :(得分:3)
您可以使用查找和擦除地图。它不像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);
}