有人可以帮助我吗?
编译此代码:
void test()
{
std::set<int> test;
test.insert(42);
test.erase(std::remove(test.begin(), test.end(), 30), test.end()); // <- Line 33
}
编译时会产生以下错误:
$ make
g++ -c -Wall -pedantic-errors -Wextra -Wunused -Werror a_star.cpp
/usr/lib/gcc/i686-pc-cygwin/4.3.4/include/c++/bits/stl_algo.h: In function `_FIter std::remove(_FIter, _FIter, const _Tp&) [with _FIter = std::_Rb_tree_const_iterator<int>, _Tp = int]':
a_star.cpp:33: instantiated from here
/usr/lib/gcc/i686-pc-cygwin/4.3.4/include/c++/bits/stl_algo.h:779: error: assignment of read-only location `__result.std::_Rb_tree_const_iterator<_Tp>::operator* [with _Tp = int]()'
make: *** [a_star.o] Error 1
答案 0 :(得分:23)
在std::set
中,元素不可修改。因此,std::set::iterator
也是不可修改的。来自this教程,第27.3.2.1节:
在简单的关联容器中, 元素是键的位置 元素是完全不可变的;该 嵌套类型迭代器和 因此const_iterator是相同的。
因此,erase-remove
成语不能按原样应用。您必须编写for
循环,并在其中使用成员函数std::set::erase
。有关详细信息,请参阅此question,此接受answer和另一个answer,但简而言之,循环如下所示
typename std::set::iterator set_iter;
for( set_iter it = s.begin(); it != s.end(); /* blank */ ) {
if( some_condition() ) {
s.erase( it++ ); // Note the subtlety here
}
else {
++it;
}
}
答案 1 :(得分:5)
擦除删除习惯用法不能与关联容器一起使用。关联容器不允许通过迭代器修改整个容器元素,这意味着不能对它们应用变异序列操作(如std::remove
)。
答案 2 :(得分:1)
如前所述,您的代码不起作用,因为您尝试修改关联容器内的序列,但是您不能这样做,因为此序列是不可变的。基本原理:set保存有序序列,通常在二叉树中。如果您被允许修改它,您可能会损坏容器并且程序会崩溃。顺便说一下,在某些情况下它仍然会发生。
您可以将代码更改为:
test.erase(30);
或者使用ArunSaha(+1)代码来处理更复杂的标准。
答案 3 :(得分:0)
如果我记得很清楚,std :: remove永远不会与std :: set元素一起使用。
由于集合不是纯数组,因此必须使用擦除。