如何从stl数据结构中删除reverse_iterator?

Dou*_* T. 14 c++ iterator stl

由于某种原因,以下代码失败.您不能简单地使用其base()方法擦除reverse_iterator.

#include <set>
#include <iostream>

int main()
{
    std::set<int> setOfInts;
    setOfInts.insert(1);
    setOfInts.insert(2);
    setOfInts.insert(3);

    std::set<int>::reverse_iterator rev_iter = setOfInts.rbegin();
    std::set<int>::reverse_iterator nextRevIter = setOfInts.rbegin();
    ++nextIter;

    while ( rev_iter != setOfInts.rend())
    {
        // Find 3 and try to erase
        if (*rev_iter == 3)
        {
            // SEGFAULT HERE
            setOfInts.erase( rev_iter.base());
        }
        rev_iter = nextRevIter;
        ++nextRevIter;
    }

}
Run Code Online (Sandbox Code Playgroud)

如何正确地做上述事情?如果reverse_iterator对应于您想要擦除的内容,那么如何删除它?

注意,遗憾的是不会使用reverse_iterator.它想要真实的东西.

Dou*_* T. 18

显然,解决方案是base()返回1关闭.对于reverse_iterator,以下标识成立:

&*(reverse_iterator(i)) == &*(i - 1) 
Run Code Online (Sandbox Code Playgroud)

或者换句话说,reverse_iterator始终是一个通过它的基础的常规迭代器.不知道为什么.

在GCC

简单地改变

        // SEGFAULT HERE
        setOfInts.erase( rev_iter.base());
Run Code Online (Sandbox Code Playgroud)

        // WORKS!
        setOfInts.erase( --rev_iter.base());
Run Code Online (Sandbox Code Playgroud)

我很清楚,为什么上面的身份才有意义.

在Visual Studio中

回到工作中并在visual studio中尝试这个,我看到上面的解决方案并不是很有效.擦除时"nextIter"变为无效.相反,你需要将擦除中的临时值保存到下一个迭代器而不是保持像上面那样的nextIter.

  set<int>::iterator tempIter = setOfInts.erase(--rev_iter.base());
  rev_iter = setOfInts.erase(tempIter);
Run Code Online (Sandbox Code Playgroud)

所以最终的解决方案是

int main()
{
    using namespace std;

    set<int> setOfInts;
    setOfInts.insert(1);
    setOfInts.insert(2);
    setOfInts.insert(3);

    set<int>::reverse_iterator rev_iter = setOfInts.rbegin();

    while ( rev_iter != setOfInts.rend())
    {
        // Find 3 and try to erase
        if (*rev_iter == 3)
        {
            cout << "Erasing : " << *rev_iter;
            set<int>::iterator tempIter = setOfInts.erase( --rev_iter.base());
            rev_iter = set<int>::reverse_iterator(tempIter);            
        }
        else
        {
            ++rev_iter;
        }
    }   

}
Run Code Online (Sandbox Code Playgroud)

注意,关联容器不会从erase返回迭代器.因此,此解决方案不适用于地图,多图等.

  • 上述标识是为了确保反向迭代器可以在所有标准位置工作,这些位置期望迭代器范围指定半开区间[first,last).如果不是这种情况,反向迭代器在std algos中将是无用的,因为'end'将被解除引用并且将跳过'begin'. (3认同)
  • 这总结了我生命中的最后几个小时:) (2认同)
  • 我认为这是因为你可以指出一个超过数组结尾但不是一个数组开始之前的数组.所以如果.rend()== i,那么i.base()== .begin(),而不是.begin() - 1(也就是UB).所以它总是一个关闭,但是当解除引用时,它返回* - .base() (2认同)