据称,当迭代器变为无效时,您不能在迭代时擦除/删除容器中的元素。删除满足特定条件的元素的(安全)方法是什么?请只是stl,no boost或tr1。
修改 如果我想删除符合特定条件的多个元素,或许使用functor和for_each或erase算法,是否有更优雅的方法?
答案 0 :(得分:34)
只要在删除迭代器后它就不会使迭代器无效:
MyContainer::iterator it = myContainer.begin();
while(it != myContainer.end())
{
if (*it == matchingValue)
{
myContainer.erase(it++);
}
else
{
++it;
}
}
答案 1 :(得分:9)
std :: vector
的示例#include <vector>
using namespace std;
int main()
{
typedef vector <int> int_vector;
int_vector v(10);
// Fill as: 0,1,2,0,1,2 etc
for (size_t i = 0; i < v.size(); ++i){
v[i] = i % 3;
}
// Remove every element where value == 1
for (int_vector::iterator it = v.begin(); it != v.end(); /* BLANK */){
if (*it == 1){
it = v.erase(it);
} else {
++it;
}
}
}
答案 2 :(得分:9)
bool IsOdd( int i )
{
return (i&1)!=0;
}
int a[] = {1,2,3,4,5};
vector<int> v( a, a + 5 );
v.erase( remove_if( v.begin(), v.end(), bind1st( equal_to<int>(), 4 ) ), v.end() );
// v contains {1,2,3,5}
v.erase( remove_if( v.begin(), v.end(), IsOdd ), v.end() );
// v contains {2}
答案 3 :(得分:3)
Viktor的解决方案具有在移除之前能够对元素执行某些操作的好处。 (我无法使用remove_if
或remove_copy_if
执行此操作。)但我更喜欢使用std::find_if
,因此我自己永远不必增加迭代器:
typedef vector<int> int_vector;
int_vector v;
int_vector::iterator itr = v.begin();
for(;;)
{
itr = std::find_if(itr, v.end(), Predicate(4));
if (itr == v.end())
{
break;
}
// do stuff with *itr here
itr = v.erase(itr); // grab a new, valid iterator
}
谓词可能是bind1st( equal_to<int>(), 4 )
或类似的东西:
struct Predicate : public unary_function<int, bool>
{
int mExpected;
Predicate(int desired) : mExpected(desired) {}
bool operator() (int input)
{
return ( input == mExpected );
}
};
答案 4 :(得分:2)
我更喜欢带有while
的版本:
typedef std::list<some_class_t> list_t;
void f( void ) {
// Remove items from list
list_t::iterator it = sample_list.begin();
while ( it != sample_list.end() ) {
if ( it->condition == true ) {
it = sample_list.erase( it );
} else ++it;
}
}
使用while
,it
循环增加for
两次没有危险。
答案 5 :(得分:2)
1.For std::vector<>
:
std::vector <int> vec;
vec.erase(std::remove(vec.begin(),vec.end(), elem_to_remove), vec.end());
2. std::map<>
始终使用std::map::erase()
std::map<int,std::string> myMap;
myMap.emplace(std::make_pair(1, "Hello"));
myMap.emplace(std::make_pair(2, "Hi"));
myMap.emplace(std::make_pair(3, "How"));
myMap.erase( 1);//Erase with key
myMap.erase(myMap.begin(), ++myMap.begin() );//Erase with range
for( auto &ele: myMap)
{
if(ele.first ==1)
{
myMap.erase(ele.first);//erase by key
break; //You can't use ele again properly
//wthin this iteration, so break.
}
}
std::list
使用std::list::erase()
答案 6 :(得分:1)
template <class Container, class Predicate>
void eraseIf( Container& container, Predicate predicate ) {
container.erase( remove_if( container.begin(), container.end(), predicate ), container.end() );
}
// pre-c++11 version
template<class K, class V, class Predicate>
void eraseIf( std::map<K,V>& container, Predicate predicate) {
typename std::map<K,V>::iterator iter = container.begin();
while(iter!=container.end()) {
iterator current = iter++;
if(predicate(*current))
container.erase(current);
}
}
// c++11 version
template<class K, class V, class Predicate>
void eraseIf( std::map<K,V>& container, Predicate predicate) {
auto iter = container.begin();
while(iter!=container.end()) {
if(predicate(*iter))
iter = container.erase(iter);
else
++iter;
}
}
答案 7 :(得分:1)
markh44是最STL-ish的反应。 但请注意,通常,通过修改容器使迭代器无效,但set和map是异常。在那里,您可以删除项目并继续使用迭代器,除非您删除了迭代器引用的项目。
答案 8 :(得分:1)
使用post-decrement运算符在递减之前返回迭代器的副本这一事实。由于在删除当前元素后递减的迭代器仍然有效,因此for循环继续按预期运行。
#include <list>
std::list<int> myList;
for(int i = 0; i < 10; ++i )
{
myList.push_back(i);
}
int cnt = 0;
for(std::list<int>::iterator iter = myList.begin(); iter != myList.end(); ++iter)
{
if( cnt == 5 )
{
myList.erase(iter--);
}
++cnt;
}
编辑:如果您尝试删除列表中的第一个元素,则不起作用....