2014-05-20 19 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(),那么你的循环将会退出。

相关问题