2014-05-20 21 views
1

好的。爲了其他(更簡單但不能說明問題)的問題,這可能看起來像,我不問這是可能的還是不可能的(因爲我已經發現了),我問是否有更輕的替代方案題。是否有可能從C++ 11的for循環中清除矢量?

我所擁有的是什麼將被視爲主類,並且在該主類中,有一個引用「世界地圖」類的變量。實際上,這個'WorldMap'類是其他類變量的容器。主類完成所有循環並更新所有活動的相應對象。在這個循環中有時候需要刪除一個位於遞歸集合內部的向量對象(如所提供的代碼所示)。重複引用必要變量作爲指向另一個指針的指針(以此類推)指向我需要的特定對象並稍後將其擦除(這是我在切換到C++之前使用的概念) 11),所以我有一個循環的範圍(也顯示在代碼中)。我的示例代碼顯示了我已經到位的想法,我想要削減乏味以及使代碼更具可讀性。

這是示例代碼:

struct item{ 
    int stat; 
}; 

struct character{ 
    int otherStat; 
    std::vector<item> myItems; 
}; 

struct charContainer{ 
    std::map<int, character> myChars; 
}; 

int main(){ 
    //... 
    charContainer box; 
    //I want to do something closer to this 
    for(item targItem: box.myChars[iter].myItems){ 
     //Then I only have to use targItem as the reference 
     if(targItem.isFinished) 
      box.myChars[iter].myItems.erase(targItem); 
    } 
    //Instead of doing this 
    for(int a=0;a<box.myChars[iter].myItems.size();a++){ 
     //Then I have to repeatedly use box.myChars[iter].myItems[a] 
     if(box.myChars[iter].myItems[a].isFinished) 
      box.myChars[iter].myItems.erase(box.myChars[iter].myItems[a]); 
    } 
} 

TLDR:我想刪除的重複調用通過使用新的範圍爲在C++ 11所示迴路的全部參考的單調乏味。

EDIT:我不是試圖一次刪除所有元素。我在問我如何在第一個循環中刪除它們。當我在外部完成它們時(通過if語句),我正在刪除它們。我將如何刪除特定的元素,而不是所有的元素?

+0

如果我這樣做了,那麼有人很有可能會走進來說:「我不知道你在問什麼或嘗試!」 – Molma

+1

那麼,你可以清楚你所要求的沒有填充的東西,它不會改變自然的答案(如結構)和不可執行的信息......這是一條很好的路線,但我會說錯在了簡潔。換句話說:一個簡短的問題可能會給你一些澄清的要求,而一個長期的問題可能會被忽略而死。 –

+0

這似乎讓你的注意力非常好:P。如果人們想立即開始追逐,還有一條TLDR消息。根據過去的經驗,我只是以這種方式進行格式化。 – Molma

回答

7

如果你只是想清除的std ::向量,有一個很簡單的方法,你可以使用:

std::vector<item> v; 

// Fill v with elements... 

v.clear(); // Removes all elements from v. 

除了這個,我想指出的是,[1] - 擦除向量中的元素需要使用迭代器,並且[2],即使您的方法被允許,如果您不小心,從for循環中清除向量中的元素也是一個壞主意。假設您的載體有5個要素:

std::vector<int> v = { 1, 2, 3, 4, 5 }; 

那麼你的循環會帶來以下影響:

  • 第一次迭代:a == 0, size() == 5。我們刪除第一個元素,那麼矢量將包含{2, 3, 4, 5}

  • 第二次迭代:a == 1, size() == 4。然後,我們刪除元素,則載體將含有{2,4,5}

  • 第三次迭代:a == 2, size() == 3。我們刪除第三個元素,我們剩下的最終結果{2,4}

因爲這實際上並沒有清空矢量,我想這不是你想要的。

相反,如果你有,你想申請刪除元素一些特定的條件,則很容易在C++ 11通過以下方式申請:

std::vector<MyType> v = { /* initialize vector */ }; 

// The following is a lambda, which is a function you can store in a variable. 
// Here we use it to represent the condition that should be used to remove 
// elements from the vector v. 
auto isToRemove = [](const MyType & value){ 
    return /* true if to remove, false if not */ 
}; 

// A vector can remove multiple elements at the same time using its method erase(). 
// Erase will remove all elements within a specified range. We use this method 
// together with another method provided by the standard library: remove_if. 
// What it does is it deletes all elements for which a particular predicate 
// returns true within a range, and leaves the empty spaces at the end. 
v.erase(std::remove_if(std::begin(v), std::end(v), isToRemove), std::end(v)); 

// Done! 
+0

一個簡單的問題:我將如何去打破擦除循環?例如,我有一個循環,我正在尋找一些東西移動到其他地方(受距離和冷卻時間等其他變量的影響),當我找到符合描述的第一個匹配項時,「break」循環。 – Molma

+1

這可以使用另一種標準庫算法'find_if'完成。您應該閱讀標準庫中提供的所有算法。你可以在這裏找到他們:http://www.cplusplus.com/reference/algorithm/ – Svalorzen

2

我刪除它們時我在外部完成了它們(通過if語句)。我將如何刪除特定的元素,而不是所有的元素?

在我看來,你看着這個錯誤的方式。編寫循環刪除序列容器中的項目始終存在問題,不建議使用。努力避免以這種方式去除物品。

當您使用容器時,應策略性地設置代碼,以便將已刪除或「即將被刪除」的項目放置在易於訪問的容器的一部分中,遠離容器中的項目你不想刪除。當你實際上想要移除它們時,你知道它們在哪裏,因此可以調用一些函數將它們從容器中排出。

已經給出了一個答案,那就是使用erase-remove(if)成語。當您撥打removeremove_if時,「不好」的項目將移動到容器的末尾。 remove(_if)的返回值是要刪除的項目的開始迭代器。然後,將此迭代器提供給vector::erase方法,以從容器中永久刪除這些項目。

另一種解決方案(但可能較少使用)是std::partition算法。 std::partition也可以將「壞」物品移動到容器的末端,但與remove(_if)不同,物品仍然有效(即,您可以將它們留在容器的末端並仍然安全地使用它們)。稍後,您可以在單獨的步驟中隨意刪除它們,因爲std::partition也會返回迭代器。

+0

這是非常有趣的,如果我只是刪除他們的if語句,但我不是。我將矢量放置在隨機刪除元素的程序中,因爲它們不再有用。這也是我在問題評論中解釋的另一種情況。在檢查迭代是否「標記爲刪除」之前,還有其他成員函數和我對每次迭代所做的更改(例如:'targItem-> function1(); targItem-> function2();'等)與評論。 – Molma

+0

我的程序已經非常大,添加它的每一位會讓很多讀者生氣,這就是我舉個例子的原因。這個代碼與實際發生的事情沒有任何關係,但是問題的要點是書面的,而其他的並非如此重要,對函數的調用等都有評論,因此爲什麼在我的問題中混淆是常見的。我也(暫時)由於個人問題而無法過分打字,但在暑假休假(避免TMI)讓我感到壓抑。 – Molma

+0

那麼,你的原始代碼顯示如下習慣用法:'1)通過我的向量。 2)如果一個項目有一定的條件,那麼做一些東西,然後刪除它。'這就是'remove_if/erase'成語,或者至少是'partition/erase'成語,正如給出的答案所解釋的那樣。 – PaulMcKenzie

0

爲什麼不能有一個標準的迭代器遍歷一個向量。這樣你可以通過傳遞一個迭代器來刪除元素。然後.erase()將返回下一個可用的迭代器。如果你的下一個迭代器是iterator :: end(),那麼你的循環將會退出。

相關問題