反向迭代器由std :: set :: erase

时间:2018-12-12 01:54:41

标签: c++11 stdset

我正在尝试删除刚刚遍历的元素。我最初忘了将s1.erase(...)的返回值存储在for循环中,以最终设置退出循环的条件。使用现在的代码方式,我希望循环无限期地继续下去。就像它最初打算的那样工作。 它看起来像std :: erase推进迭代器,并将值存储在rit中。我找不到任何解释此行为的文档。

https://en.cppreference.com/w/cpp/container/set/erase表示必须存储返回的迭代器。 set :: erase的所有参数都按值传递,那么反向迭代器如何进行高级处理?

此循环如何完成?

std::set<int> s1;
s1.insert(20);
s1.insert(30);
s1.insert(50);

auto rit = s1.rbegin();

for (; rit!= s1.rend();)
{
    std::cout << "rit is " << *rit << " size is " << s1.size() << std::endl;
    s1.erase(std::next(rit).base());
    std::cout << "rit after erase is " << *rit << std::endl;
}

输出为

rit是50,大小是3

擦除后

rit为30

rit是30,大小是2

擦除后

rit为20

rit是20,大小是1

分段错误

1 个答案:

答案 0 :(得分:2)

回想一下,reverse_iterator::base()始终是明显迭代器值后面的一个元素。例如,在auto rit = s1.rbegin()之后,*rit返回最后一个元素,而rit.base() == s1.end()返回。

换句话说,*rit == *prev(rit.base())

在循环中,最初为rit.base() == s1.end()。然后std::next(rit).base()指向最后一个元素;该元素被删除。在std::set中,删除元素只会使对该元素的迭代器无效,而对其他元素则无效。 s1.end()仍然是有效的迭代器,rit也是有效的迭代器,其中rit.base()仍然等于s1.end()。因此,在循环的下一次迭代中,您将再次擦除最后一个元素,然后再次离开rit.base() == s1.end()。依此类推。

在某些时候,最后一个元素被删除,s1变为空,然后*rit表现出未定义的行为。回想一下*rit == *prev(rit.base()),但是已经没有先前的元素了。