15

由于某种原因,以下代码失败。您不能简单地使用它的 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;
    }

}

如何正确地执行上述操作?给定一个与您要擦除的内容相对应的 reverse_iterator,您如何擦除它?

请注意,不幸的是,擦除不会采用 reverse_iterators。它想要真实的东西。

4

4 回答 4

18

显然解决方案是 base() 返回的是 1 。以下标识适用于 reverse_iterator:

&*(reverse_iterator(i)) == &*(i - 1) 

或者换句话说,reverse_iterator 始终是它作为基础的常规迭代器的一次传递。不知道为什么。

在海合会

简单地改变

        // SEGFAULT HERE
        setOfInts.erase( rev_iter.base());

        // WORKS!
        setOfInts.erase( --rev_iter.base());

我当然很好奇为什么上面的身份是有意义的。

在 Visual Studio 中

重新开始工作并在 Visual Studio 中尝试此操作,我发现上述解决方案不太奏效。“nextIter”在擦除时变得无效。相反,您需要从擦除中保存临时值以获取下一个迭代器,而不是像上面那样保留 nextIter。

  set<int>::iterator tempIter = setOfInts.erase(--rev_iter.base());
  rev_iter = setOfInts.erase(tempIter);

所以最终的解决方案是

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;
        }
    }   

}

请注意,关联容器不会从擦除返回迭代器。所以这个解决方案不适用于地图、多地图等。

于 2008-12-31T23:25:32.003 回答
3

当您使用反向迭代器进行迭代并希望使用 base() 修改其容器时,请始终牢记 reverse_iterator 始终基于原始顺序的下一个迭代器。这有点不直观,但实际上使代码更简单:

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

    typedef std::set<int>::reverse_iterator RevIter;

    RevIter rev_iter = setOfInts.rbegin();
    while (rev_iter != setOfInts.rend())
    {
        // Find 3 and try to erase
        if (*rev_iter == 3)
            setOfInts.erase(--rev_iter.base());

        ++rev_iter;
    }
}

在此示例中,不需要保留“下一个”迭代器,因为基本迭代器没有失效!(我们在处理普通迭代器时确实需要它。)

反向迭代器的行为在处理单个项目时会产生奇怪的逐一困难,但实际上它简化了范围:

riValue = find(riEnd.base(), riBegin.base(), value);

使用完全相同的对象(以相反的顺序)

iValue = find(riBegin, riEnd, value);
于 2009-05-04T16:57:45.210 回答
0

1 来自map::erase,我们知道它只需要iterator;

2 来自reverse_iterator::base,我们知道&*(reverse_iterator ( i ) ) == &*( i – 1 ).

因此,您可以使用 erase(--r_v.base()) 来擦除“r_v”(和“current-1”)指向的元素:

            r_v+1            r_v          r_v-1
           current-2      current-1      current
于 2014-01-08T07:27:23.040 回答
-3

使用迭代器本身调用erase(无需使用base)。

#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();

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

此外,您不需要单独的“下一个”迭代器(参见上面的更改)。一个更好的方法是使用std::remove_if(或类似的函数)。

于 2008-12-31T23:22:57.767 回答