c++ - 在使用迭代器和 pop_back 循环时出现单一迭代器错误

标签 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_DEBUG (g++ -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 应该在无效的迭代器上运行。但是为什么代码没有报错呢?

最佳答案

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

For a reverse iterator r constructed from an iterator i, the relationship &*r == &*(i-1) is always true (as long as r is dereferenceable); thus a reverse iterator constructed from a one-past-the-end iterator dereferences to the last element in a sequence.

然后我们做 std::deque::pop_back() ,我们使:

Iterators and references to the erased element are invalidated. The past-the-end iterator is also invalidated. Other references and iterators are not affected.

rbegin()end() 构建。在我们第一次递增 it 之后,it 将取消对 2 的引用,但它的底层基础迭代器指向 3 - 那是被删除的元素。所以引用它的迭代器包括你现在高级的反向迭代器。这就是它无效的原因,也是您看到所看到的错误的原因。

反向迭代器很复杂。


您可以将它重新分配给 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();
}

关于c++ - 在使用迭代器和 pop_back 循环时出现单一迭代器错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37280744/

相关文章:

c++ - 将类构造函数作为方法调用

c++ - boost 异步操作不起作用(对我来说)

C++11 POD 结构初始化错误

c++ - 通过迭代器调用函数?

python - Python 中的 zip 对象不是迭代器吗?

c# - SetupDiEnumDriverInfo 始终返回错误 259(没有更多可用数据)

c++ - memset() 在构造函数中初始化对象?

c++ - 在 std::unordered_map 中使用模板化键

c++ - C++11 是否允许(不需要)释放/获取 volatile 关键字的语义

c++ - 在迭代 vector 时使用 return 语句退出循环是否安全?