向量:rend()被erase()无效

时间:2011-03-08 17:30:40

标签: c++ visual-c++ vector erase

根据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错误。

5 个答案:

答案 0 :(得分:4)

您的程序调用未定义的行为。因此,编译器都不正确。

根据标准,std::vector<int>::reverse_iteratorstd::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 ++只是在引擎盖下使用指针,所以它看起来都能正常工作。

如果您尝试从向量中删除匹配元素,则更好的方法是使用removeremove_if