反向迭代器由std::set::erase进行高级处理



我正试图擦除刚刚遍历的元素。一开始我忘了在for循环中存储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

分段故障

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

相关内容

  • 没有找到相关文章

最新更新