删除循环内的向量元素

时间:2011-12-25 09:12:32

标签: c++ vector erase

我知道这个问题有类似问题,但我没有设法通过他们的帮助找到我的代码。我只想通过检查循环内该元素的属性来删除/删除向量的元素。我怎样才能做到这一点?我尝试了以下代码,但收到了错误的模糊消息:

'operator ='功能在'播放器'中不可用。

 for (vector<Player>::iterator it = allPlayers.begin(); it != allPlayers.end(); it++)
 {
     if(it->getpMoney()<=0) 
         it = allPlayers.erase(it);
     else 
         ++it;
 }

我该怎么办?

更新:您认为问题vector::erase with pointer member是否属于同一问题?我需要一个赋值运算符吗?为什么?

6 个答案:

答案 0 :(得分:112)

您不应在it循环中增加for

for (vector<Player>::iterator it=allPlayers.begin(); 
                              it!=allPlayers.end(); 
                              /*it++*/) <----------- I commented it.
{

   if(it->getpMoney()<=0) 
      it = allPlayers.erase(it);
  else 
      ++it;
 }

注意注释部分;那里不需要it++,因为it在for-body本身中会增加。

对于错误“'operator ='函数在'播放器'中不可用”,它来自erase()的使用,它在内部使用operator=来移动元素在向量中。要使用erase(),类Player的对象必须是可分配的,这意味着您需要为operator=类实现Player

无论如何,你应该尽可能避免使用raw loop 1 ,而应该更喜欢使用算法。在这种情况下,流行的Erase-Remove Idiom可以简化您正在做的事情。

allPlayers.erase(
    std::remove_if(
        allPlayers.begin(), 
        allPlayers.end(),
        [](Player const & p) { return p.getpMoney() <= 0; }
    ), 
    allPlayers.end()
); 

1。这是我曾经看过的the best talk by Sean Parent之一。

答案 1 :(得分:12)

if(allPlayers.empty() == false) {
    for(int i = allPlayers.size() - 1; i >= 0; i--) {
        if(allPlayers.at(i).getpMoney() <= 0) {
            allPlayers.erase( allPlayers.begin() + i ); 
        }
    }
}

这是我删除vector中元素的方法。 这很容易理解,也不需要任何技巧。

答案 2 :(得分:11)

忘记循环并使用std或boost范围算法。 在Lambda中使用Boost.Range它看起来像这样:

boost::remove_if( allPlayers, bind(&Player::getpMoney, _1)<=0 );

答案 3 :(得分:5)

您的具体问题是您的Player类没有赋值运算符。您必须使“播放器”可复制或移动,以便将其从矢量中移除。这是因为向量需要是连续的,因此需要重新排序元素以填充删除元素时创建的间隙。

此外:

使用标准算法

allPlayers.erase(std::remove_if(allPlayers.begin(), allPlayers.end(), [](const Player& player)
{
    return player.getpMoney() <= 0;
}), allPlayers.end());

如果你有提升,甚至更简单:

boost::remove_erase_if(allPlayers, [](const Player& player)
{
    return player.getpMoney() <= 0;
});

如果你不支持C ++ 11 lambdas,请参阅TimW的答案。

答案 4 :(得分:4)

或者向后循环。

for (vector<Player>::iterator it = allPlayers.end() - 1; it != allPlayers.begin() - 1; it--)
    if(it->getpMoney()<=0) 
        it = allPlayers.erase(it);

答案 5 :(得分:3)

C ++ 11引入了一个新的函数集合,将在这里使用。

allPlayers.erase(
    std::remove_if(allPlayers.begin(), allPlayers.end(),
        [](auto& x) {return x->getpMoney() <= 0;} ), 
    allPlayers.end()); 

然后你可以获得不必进行相当多的终端元素移动的优势。