2011-12-25 133 views
53

我知道這個問題有類似的問題,但我沒有設法通過他們的幫助找到我的代碼的方式。我只想通過在循環內檢查此元素的屬性來刪除/刪除矢量的元素。我怎樣才能做到這一點?我嘗試了下面的代碼,但收到錯誤的模糊消息:刪除循環中的矢量元素

'operator ='功能在'Player'中不可用。

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問題屬於同一問題嗎?我是否需要一個賦值操作符?爲什麼?

+2

請注意,使用std :: remove_if可能會好很多。請參閱[this](http://lazarenko.me/2013/01/14/erasing-vector-the-smart-way/)帖子瞭解詳情。 – 2013-01-14 15:12:34

+0

使用[this](http://stackoverflow.com/questions/347441/erasing-elements-from-a-vector)文章中描述的擦除/刪除習慣用法。 – 2017-04-01 14:33:25

回答

89

你不應該在for循環增量it

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在身體本身中增加了。

至於錯誤「‘運算符=’功能處於「播放」不可用」,它來自的erase()使用其內部使用operator=移動向量中的元素。爲了使用erase(),類Player的對象必須是可分配的,這意味着您需要爲Player類實現operator=

+1

我試過但我收到了同樣的錯誤。當我刪除上述循環(刪除)程序編譯。因此,刪除/擦除存在問題。類Player的成員是指向其他對象的指針。在這種情況下他們成了什麼? – arjacsoh 2011-12-25 09:43:43

+1

實際上,錯誤來自std :: vector.erase,它使用賦值運算符來移動元素以保持矢量的連續性。 – ronag 2011-12-25 11:52:27

+0

這個習語有沒有名字? – sp2danny 2015-05-16 12:36:08

11

忘掉循環並使用std或boost範圍algorthims。
使用Boost.Range連接LAMBDA它應該是這樣的:

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

+1。這是[要走的路](http://lazarenko.me/2013/01/14/erasing-vector-the-smart-way/)! – 2013-01-14 15:13:44

+24

-1不真誠的答案。例如,如何在不知道如何在較低層次上完成所述算法的情況下編寫所述算法。不是每個人都可以生活在抽象天堂。關於爲嘗試學習Javascript的人回答'USE JQUERY !! 1!'有用。 – 2013-09-26 17:53:04

+1

此算法僅在您只想刪除元素時纔有用。想想情況,'if(condition)it = x.erase(it); else {file << * it; ++它; }'。正如你可以看到當元素不適合刪除時你想做其他事情,你不能使用'remove_if'。即使你使用它,你也可能不得不再次遍歷循環。 – iammilind 2015-07-13 10:06:07

5

您的具體問題是,你的Player類沒有賦值運算符。您必須讓「玩家」可以複製或移動,才能將其從矢量中移除。這是由於該矢量需要連續,因此需要重新排列元素以填充刪除元素時創建的間隙。

另外:

使用std算法

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; 
}); 

見TIMW的答案,如果你沒有對C++ 11的支持lambda表達式。

+0

我認爲這個問題就是你提到的。然而,我已經添加了一個分配運算符作爲Player&operator =(Player.h文件中的const Player & rhs);,但我仍然得到錯誤(帶有不同的消息)。我是否最終需要一個拷貝構造函數? – arjacsoh 2011-12-25 11:52:25

+1

您還應該實現一個拷貝構造函數。如果您不發佈相關錯誤或代碼,很難說出問題所在。 – ronag 2011-12-25 11:54:22

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

這是我的方法來刪除向量中的元素。 這很容易理解,並不需要任何技巧。

+1

只是一個快速的評論:你可以用(!allPlayers.empty())替換(allPlayers.empty()== false)。 這是因爲empty()返回一個布爾類型:如果vector爲空,它將返回true。使用「not」運算符就像在說「如果vector不是空的」。只是爲了美化你的代碼:) – Floella 2016-10-17 13:04:17

+0

@Anarelle謝謝! – 2016-11-03 06:47:52

+0

非常好。謝謝。 – galian 2017-12-12 16:06:40

4

或者向後循環。

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

C++ 11引入了一個新的函數集合,這些函數將在這裏使用。

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

然後你得到的好處是不必做太多的結束元素轉移。

+1

'std :: vector :: erase(iterator)'刪除迭代器指向的單個元素。在你的例子中,它將嘗試去除由'std :: remove_if'返回的迭代器指向的元素 - 這是一個傳遞端迭代器,所以這幾乎肯定是不正確的(並且會導致崩潰)。它應該是:'allPlayers.erase(std :: remove_if(...),allPlayers.end())'而不是刪除範圍內的所有元素。 – Ellis 2018-03-07 19:42:39

+1

@Ellis更新,謝謝。 – UKMonkey 2018-03-07 20:36:12