C ++迭代器是否包含对底层对象的引用?

时间:2016-08-18 09:07:13

标签: c++ reference iterator

我似乎无法找到有关迭代器是否保留它们正在迭代的基础对象的更多信息。

如果我创建一个迭代器,那么提供它的对象超出范围,迭代器的存在是否会阻止它被破坏?

这是一个非常简单的例子,仅用于说明场景:

// This class takes a copy of iterators to use them later
class Data {
  public:
    Data(std::vector<int>::iterator start, std::vector<int>::iterator end)
      : start(start),
        end(end)
    {}

    void show() {
      // Use this->start and this->end for some purpose
    }

  private:
    std::vector<int>::iterator start;
    std::vector<int>::iterator end;
};

Data test() {
  std::vector<int> v{1, 2, 3};
  Data d(v.begin(), v.end());
  d.show(); // this would be ok
  return d;
}

int main(void) {
  Data d = test();
  d.show();  // What happens here?
}

在此示例中,Data对象正在存储迭代器的副本,这对于第一次show()调用很好。但是,在第二次show()调用时,提供迭代器的原始对象不再存在。

迭代器是否保留对象,直到它们全部被销毁为止,或者一旦原始对象超出范围,迭代器就会失效?

这里是one reference of many,它没有说明以某种方式发生了什么(或者甚至是否结果是'未定义'。)

3 个答案:

答案 0 :(得分:6)

迭代器通常不拥有他们迭代的数据,没有。事实上,他们很少(如果有的话)甚至意识到拥有数据的对象;例如,向量迭代器通常只是指针,它们不知道任何向量或其生命周期。即使那些没有被实现为指针的迭代器(大多数也是如此)都可以被认为是一种&#34;指针&#34;,并且这样处理:它们很容易变成悬空。

你的例子有UB,因为你第二次在show()内取消引用无效的迭代器。

如果容器超出范围,则所有迭代器都将失效。事实上,there are all manner of reasons why an iterator may become invalidated,例如当该操作导致容量扩展时添加到向量。

可以找到类型的迭代器&#34;拥有&#34;数据,而不是迭代在其他地方找到的某些集合(例如Boost's counting iterators),但这些是利用C ++提供神奇函数的神奇属性,而不是C ++定义的迭代器的固有属性。

答案 1 :(得分:2)

迭代器通常只有在其原始容器或“序列”未被更改时才有效,因为更改可能导致内存重新分配和内存移动。由于原始容器中的迭代器通常引用内存,因此所述容器中的更改可能会使迭代器无效。

现在,超出范围的容器会执行析构函数。这显然会更改容器,因此任何迭代器都将在此过程中失效。

答案 2 :(得分:1)

首先,迭代器没有引用它迭代的对象的接口。它只实现指针语义,因此您可以将其视为抽象指针。当然,它的内部实现可能包含指向该对象的指针,但在实际实现中它是不太可能的。

其次,当您的容器被销毁时(当它超出范围时),容器中的所有对象也将被销毁。因此,在销毁容器后,迭代器将变为无效。在递增之后,递减和解除引用迭代器将导致未定义的行为。