【问题标题】:rbegin() in std::list is never equal to an iterator pointing into the list?std::list 中的 rbegin() 永远不等于指向列表的迭代器?
【发布时间】:2017-03-23 18:30:37
【问题描述】:

为什么下面的代码会崩溃?

int main(int argc, const char * argv[]) {


std::list<int> aList={1,2,3,4,5};

std::list<int>::reverse_iterator i=aList.rbegin();
i++;
i++;

assert(*i==3);//assertion passes as expected


while (i!=aList.rbegin()) { //never becomes false
      aList.pop_back(); //segmentation fault

}
assert(*(aList.rbegin())==3);

return 0;
}

我假设 rbegin 最终会等于 i 并停止循环;但是没有发生。

注意我做了以下解决方法,仍然好奇上面的代码有什么问题

size_t  differance =std::distance( aList.rbegin(),i);

while (differance >0) {
    aList.pop_back();
    differance--;
}
assert(*aList.rbegin()==3);

【问题讨论】:

  • 请不要将容器名称与变量名称混用
  • while (differance &gt;0) { 不是解决办法

标签: c++ list stl


【解决方案1】:

std::list::rbegin() 返回一个迭代器,该迭代器引用哨兵列表末尾节点,但取消引用存储在前一个节点中的值(在您的情况下为 5)。此行为适用于 std::list 的任何反向迭代器:取消引用反向迭代器时从中获取值的节点是迭代器实际指向的节点之前的节点。

像这样可视化它,根据迭代器引用的元素:

rend() <-------- rbegin()
  |                 |
  1     2 3 4 5   (end)
  |                 |
begin() --------> end()

这意味着取消引用值 3 的迭代器实际上在内部引用了值为 4 的元素。 当值 4 从列表中删除时,迭代器值存储在 @987654325 @ 变得无效,此时您无法推断其行为。它可能(并且应该)不等于所有其他迭代器。

您可以通过在*i == 3 时写出*(i.base()) 的值来验证是否属于这种情况。你会看到*(i.base()) == 4

所以你的问题不是 rbegin() 迭代器“永远不等于指向列表的迭代器”,你的问题是你正在删除迭代器内部指向的元素,然后现在尝试比较它- rbegin() 的迭代器无效。

考虑使用aList.erase() 而不是您的循环。由于您想从值为 4 的元素中删除到数组末尾,i.base() 已经为您提供了一个迭代器,您可以直接将其传递给aList.erase()

aList.erase(i.base(), aList.end());

【讨论】:

  • 好吧 rbegin.base() == end()
  • @MalMa 是的,准确地说。而当涉及到反向迭代器的失效时,反向迭代器i在正向迭代器i.base()失效时也会失效。
【解决方案2】:

看起来你已经完全颠倒了,增加一个反向迭代器将它向后移动。

pop_back() 将使最后一个元素的迭代器无效,因此循环中的段错误。你应该做一个pop_front() 并检查(i !=rend())

【讨论】:

  • pop_front ?我想删除所有元素过去 i 即 4,5
猜你喜欢
  • 2012-04-22
  • 1970-01-01
  • 1970-01-01
  • 2020-01-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-29
  • 1970-01-01
相关资源
最近更新 更多