我正试图擦除刚刚遍历的元素。一开始我忘了在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())
,但已经没有以前的元素了。