在使用iterator和pop_back进行循环时出现奇异的迭代器错误

时间:2016-05-17 15:41:26

标签: c++ c++11 iterator reverse-iterator

给出以下代码(比如说它名为deque.cpp

#include <cstdio>
#include <deque>

int main()
{
  std::deque<int> d = {1, 2, 3};
  for (auto it = d.rbegin(); it != d.rend();) {
    printf("it: %d\n", *it);
    ++it;
    d.pop_back();
  }
  return 0;
}

使用g++ -std=c++11 -o deque deque.cpp进行编译,运行良好:

$ ./deque
it: 3
it: 2
it: 1

但如果使用-D_GLIBCXX_DEBUGg++ -std=c++11 -o deque_debug deque.cpp -D_GLIBCXX_DEBUG进行编译,则会出现以下错误:

$ ./deque_debug
it: 3
/usr/include/c++/4.8/debug/safe_iterator.h:171:error: attempt to copy-
    construct an iterator from a singular iterator.
...

看起来第二个循环的++it是从单个迭代器构造的。 但我想在第一个循环的++it之后,迭代器指向2,而pop_back()不应该使它失效。那么为什么会发生错误?

注意:我知道代码可以重写如下:

  while (!d.empty()) {
    auto it = d.rbegin();
    printf("it: %d\n", *it);
    d.pop_back();
  }

错误将消失。

但我确实想知道错误代码到底发生了什么。 (这是否意味着反向迭代器的剂量实际上并没有指向我期望的节点,而是它之后的节点?)

更新: @ Barry的回答解决了这个问题。 请允许我提出一个额外的相关问题:代码

  for (auto it = d.rbegin(); it != d.rend();) {
    printf("it: %d\n", *it);
    d.pop_back();
    ++it;   // <== moved below pop_back()
  }

应该是错误的,其中++it应该在无效的迭代器上运行。但为什么代码不会导致错误?

2 个答案:

答案 0 :(得分:5)

这里的问题源于反向迭代器实际上是什么。 reverse iterator的相关关系是:

  

对于从迭代器r构造的反向迭代器i,关系&*r == &*(i-1)始终为真(只要r是可解除引用的);因此,一个反向迭代器由一个过去的结束迭代器构造,引用序列中的最后一个元素。

当我们执行std::deque::pop_back()时,我们会失效:

  

对擦除元素的迭代器和引用无效。过去的迭代器也会失效。其他引用和迭代器不受影响。

rbegin()end()构成。在我们第一次递增it之后,it将取消引用2但其底层基础迭代器指向3 - 这是已擦除的元素。所以引用它的迭代器包括你现在先进的反向迭代器。这就是为什么它失效了,这就是你看到你所看到的错误的原因。

反向迭代器很复杂。

您可以将其重新分配给it,而不是递增rbegin()

for (auto it = d.rbegin(); it != d.rend();) {
    printf("it: %d\n", *it);
    d.pop_back();
    // 'it' and 'it+1' are both invalidated
    it = d.rbegin();
}

答案 1 :(得分:0)

从底层容器中擦除使迭代器无效。引用规则:

  

如果

,迭代器不可解除引用      
      
  • 他们是过去的终极迭代者   (包括指向数组末尾的指针)或者在开始之前   迭代器。这样的迭代器可以在特定的情况下是可解除引用的   实现,但库从不假设它们是。
  •   
  • 它们是单数迭代器,即与任何序列无关的迭代器。空指针,以及默认构造的指针   (持有不确定的价值)是单数的
  •   
  • 他们被宣告无效   对序列的迭代器无效操作之一   他们参考。
  •   

您的代码导致迭代器被pop_back操作无效,因此根据上面的第三点,它变为不可解除引用。

while循环中,通过在每次循环重复中获取(新)有效迭代器来避免此问题。