std::list存在erase与push_back操作时如何正确通过reverse_iterator删除元素
反向迭代器base()的核心偏移规则
C++标准对reverse_iterator的base()方法有明确规定:反向迭代器指向的元素,是它base()返回的正向迭代器指向的前一个元素,即 *rit == *std::prev(rit.base())。
这个设计是为了让正向和反向的区间表示完全统一:正向迭代器的[begin(), end())区间,刚好对应反向迭代器[rbegin(), rend())的逆序全量元素,rbegin().base() == end()、rend().base() == begin()完全符合这个偏移规则。
问题1:为什么你当前的删除逻辑不符合预期
回到你的场景:
你插入9后拿到s = l.rbegin(),此时s指向9,s.base() == l.end();后续插入10时,std::list的插入操作不会失效已有迭代器,s仍然指向9,但此时s.base()变成了指向10的正向迭代器。
你不需要对s调用next,你调用std::next(s)相当于让反向迭代器沿着逆序方向(往容器头部)移动一位,指向的元素变成8,它的base()对应指向9的正向迭代器,按照逻辑本该删除9,你实际删除10大概率是实际运行时的迭代器指向和你预期不一致,本质是你对base()的偏移规则理解有误。
问题2:如何通过已保存的反向迭代器正确删除元素
按照标准的偏移规则,你只需要给base()返回的正向迭代器往前偏移一位,就能拿到反向迭代器指向元素对应的正向迭代器,直接传给erase即可:
// 正确删除反向迭代器s指向的元素 l.erase(std::prev(s.base()));
这个写法通用且符合标准要求,只要你保存的反向迭代器本身没有失效,就可以正确删除对应元素。
补充注意点
std::list的erase方法只会使被删除元素的迭代器失效,其他未被删除元素的迭代器(正向、反向均可)都可以正常使用。- 不要随意对反向迭代器调用
next/prev后再取base,除非你明确知道偏移后的指向,避免出现访问越界或者操作错误元素的问题。
内容的提问来源于stack exchange,提问作者nick
相关产品推荐
相关产品推荐

