2010-09-19 100 views
12

以前有关于这个问题的几个问题;我的理解是,调用std::vector::erase只会使之后位于处的迭代器无效。但是,在擦除一个元素之后,该位置上的迭代器是否仍然有效(当然,在擦除后它不指向end())?std ::向量迭代器失效

我对如何实现向量的理解似乎表明迭代器绝对可用,但我不完全确定它是否会导致未定义的行为。

作为我正在谈论的一个示例,下面的代码将从矢量中删除所有奇数整数。此代码是否会导致未定义的行为?

typedef std::vector<int> vectype; 
vectype vec; 

for (int i = 0; i < 100; ++i) vec.push_back(i); 

vectype::iterator it = vec.begin(); 
while (it != vec.end()) { 
    if (*it % 2 == 1) vec.erase(it); 
    else ++it; 
} 

该代码在我的机器上运行良好,但这并不能说服我,它是有效的。

回答

31

擦除的元件后,在该位置仍然有效迭代

否;迭代器中或之后传递给erase的所有迭代器均失效。

但是,erase会返回一个新的迭代器,该迭代器指向刚刚删除的元素之后的元素(如果没有这样的元素,则返回到末尾)。你可以使用这个迭代器继续迭代。


注意,去除奇数元素的该特定方法是非常低效的:每次删除元素,所有元素的它有后要被移动一个位置,以在载体中的左(这是O( ))。您可以使用erase-remove idiom(O(n))更高效地完成此任务。您可以创建一个is_odd谓:

bool is_odd(int x) { return (x % 2) == 1; } 

那么这可以传递给remove_if

vec.erase(std::remove_if(vec.begin(), vec.end(), is_odd), vec.end()); 
+1

为什么你传递'通过const引用,而不是通过x'值? – fredoverflow 2010-09-20 08:13:35

+0

@Fred:没有特别的理由;感谢您指出了这一点。 – 2010-09-20 13:21:51

+0

@James但是上面提供的代码是如何工作的,因为擦除会使迭代器失效? – Kapil 2016-07-06 00:53:12

0

或者:

class CIsOdd 
{ 
public: 
    bool operator()(const int& x) { return (x % 2) == 1; } 
}; 

vec.erase(std::remove_if(vec.begin(), vec.end(), CIsOdd()), vec.end()); 
+1

为什么通过const引用而不是按值传递'x'? – fredoverflow 2010-09-20 08:14:01

+2

问题:为什么人们经常喜欢这里的方法(只有operator()重载的函数,即没有状态/数据)与James McNellis上面的答案中的简单独立函数相比?我知道他们都会工作,但我通常采取与詹姆斯相同的方法,对我来说,这似乎更简单和更明显。在某个时候,我开始问自己:“我错过了什么?”如果只是个人喜好,那很好。 – Dan 2010-09-20 19:28:24

+0

@FredOverflow,x可以是结构体,@Dan,...和operator()该结构体的成员 – ssianky 2010-09-21 02:15:30