【问题标题】:Reverse iterator is being advanced by std::set::erasestd::set::erase 正在推进反向迭代器
【发布时间】:2018-12-12 01:54:41
【问题描述】:

我正在尝试擦除刚刚遍历到的元素。我最初忘记将 s1.erase(...就像它最初打算工作的方式一样。 看起来 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

分段错误

【问题讨论】:

    标签: c++11 stdset


    【解决方案1】:

    回想一下,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()),但已经没有之前的元素了。

    【讨论】:

      猜你喜欢
      • 2010-12-10
      • 1970-01-01
      • 1970-01-01
      • 2014-08-07
      • 1970-01-01
      • 1970-01-01
      • 2021-09-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多