由于某种原因,以下代码失败。您不能简单地使用其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_iterator。它想要真实的东西。

有帮助吗?

解决方案

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

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

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

在GCC

只需更改

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

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

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

在Visual Studio中

回到工作中并在visual studio中尝试这个,我看到上面的解决方案不太有效。 “nextIter”是指“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;
        }
    }   

}

注意,关联容器不会从erase返回迭代器。所以这个解决方案不适用于map,multimap等。

其他提示

当您使用反向迭代器进行迭代并希望使用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);

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

2来自 reverse_iterator :: base ,我们知道&amp; *(reverse_iterator(i))==&amp; *(i&#8211; 1)。

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

            r_v+1            r_v          r_v-1
           current-2      current-1      current

使用迭代器本身调用 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 (或类似的函数)。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top