根据C ++规范(23.2.4.3),vector :: erase()只会使“擦除点之后的所有迭代器和引用”无效
因此,当使用reverse_iterators传递所有向量成员时,当前迭代器上的擦除不会导致rend()成员失效。
此代码将在G ++下运行,但会在Windows(VS2010)上提供运行时异常:
#include <vector>
using namespace std;
int main()
{
vector<int> x;
x.push_back(1);
x.push_back(2);
x.push_back(3);
//Print
for(vector<int>::const_iterator i = x.begin(); i != x.end(); ++i)
printf("%d\n", *i);
//Delete second node
for(vector<int>::reverse_iterator r = x.rbegin(); r != x.rend(); ++r)
if(*r == 2)
x.erase((r+1).base());
//Print
for(vector<int>::const_iterator i = x.begin(); i != x.end(); ++i)
printf("%d\n", *i);
return 0;
}
错误很有趣:
表达式:向量迭代器不可递减
在第二次运行时给出第二个for循环的行。递减引用reverse_iterator的内部“当前”迭代器成员,每当reverse_iterator递增时递减。
有人能解释一下这种行为吗?
感谢。
修改
我认为这个代码示例更好地表明它不是r的问题,而是rend():
//Delete second node
for(vector<int>::reverse_iterator r = x.rbegin(); r != x.rend();)
{
vector<int>::reverse_iterator temp = r++;
if(*temp == 2)
x.erase((temp+1).base());
}
擦除后输入时for循环中出现vector iterators incompatible
错误。
答案 0 :(得分:4)
您的程序调用未定义的行为。因此,编译器都不正确。
根据标准,std::vector<int>::reverse_iterator
是std::reverse_iterator<std::vector<int>::iterator>
的typedef。指定std::reverse_iterator<Iter>
的实现具有protected
成员Iter current;
,并且reverse_iterator
的所有其他成员和函数都是根据成员{{1}的行为指定的。 }。
假设我们有current
,其中r == reverse_iterator(i)
是i
的有效迭代器。然后,每一项都由标准保证。
std::vector<int> x;
在调用r.current == i
(r+1).current == (i-1)
(r+1).base() == (i-1)
时,x.erase((r+1).base());
之后的所有迭代器都无效。当然,这包括i-1
,因此也包括i
。
您的程序尝试评估的下一件事是r.current
。此表达式被指定为具有效果++r
。但是由于--r.current;
无效,因此该表达式为Undefined Behavior; r.current
也是如此。
答案 1 :(得分:3)
reverse_iterator
通常只是普通迭代器的包装器,因此递增反向迭代器可能会减少下面的一个迭代器。类似地,rbegin
将返回一个位于容器中所有元素之后的迭代器,因此它将以相同的方式失效。
答案 2 :(得分:2)
这是一个更好的方法来做你想做的事情:
struct CustomRemove
{
bool operator()(int i)
{
return (i == 2);
}
};
int main()
{
std::vector<int> x;
x.push_back(1);
x.push_back(2);
x.push_back(3);
CustomRemove custom_remove;
std::copy(x.begin(), x.end(), std::ostream_iterator<int>(std::cout, "\n"));
x.erase(std::remove_if(x.begin(), x.end(), custom_remove), x.end());
std::copy(x.begin(), x.end(), std::ostream_iterator<int>(std::cout, "\n"));
return 0;
}
答案 3 :(得分:1)
reverse_iterator在内部将正常迭代器存储到其当前位置之后的位置。它必须这样做,因为rend()否则必须在begin()之前返回一些东西,这是不可能的。所以你最终会意外地使你的base()迭代器失效。
答案 4 :(得分:0)
由于(r+1).base()
和r
有效地指向相同的元素,因此删除(r+1).base()
确实会使r
无效。很可能g ++只是在引擎盖下使用指针,所以它看起来都能正常工作。
如果您尝试从向量中删除匹配元素,则更好的方法是使用remove
或remove_if
。