反向迭代器正在推进 std::set::erase

Reverse iterator is being advanced by std::set::erase

我正在尝试擦除我刚刚遍历的元素。我最初忘记将 return 的 s1.erase(... 值存储在 for 循环中以最终设置退出循环的条件。按照现在的代码方式,我希望循环无限期地继续。但它的工作方式正是它最初打算工作的方式。 看起来 std::erase 推进迭代器并将值存储在 rit 中。我找不到任何解释此行为的文档。

https://en.cppreference.com/w/cpp/container/set/erase 表示必须存储迭代器 returned。 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;
}

输出为

尺码是 50 尺码是 3

擦除后的 rit 为 30

尺码是 30 尺码是 2

擦除后的 rit 为 20

尺码为 20 尺码为 1

分段错误

回想一下,reverse_iterator::base() 始终是表观迭代器值后面的一个元素。例如,在auto rit = s1.rbegin()*rit、returns最后一个元素之后,而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()),但是没有前面的元素了。