2016-08-18 81 views
5

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

如果我创建一个迭代器,那么提供它的对象超出了作用域,迭代器的存在是否阻止它被销毁?

这里是一个非常简单的例子只是为了说明的情形:

// 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不说会发生什么的一种方式或其他(甚至是否这样做的结果是“不确定”。)

+7

迭代器在指针上建模。粗略地说,如果一个指针不能做一个高级的事情X,那么迭代器也不能。 –

+0

是的,迭代器将失效,结果是未定义的。 – songyuanyao

+1

为了解决您的具体情况:销毁容器将使所有迭代器无效。 –

回答

5

迭代器通常不拥有它们迭代的数据,不。事实上,他们很少(如果曾经)知道拥有数据的对象的;例如,向量迭代器通常只是指针,它们不知道任何向量或其生命周期。即使那些没有作为指针实现的迭代器(这些指针也是大多数)可能被认为是一种“指针”,并且这样对待:它们很容易变成悬挂。

您的示例具有UB,因为您将在第二次取消引用show()中的无效迭代器。

如果你的容器超出了范围,那么你的所有迭代器都会失效。实际上,there are all manner of reasons why an iterator may become invalidated,例如在该操作导致容量扩展时添加到向量中。

有可能找到,而不是遍历其他地方找到(如Boost's counting iterators)一些集合迭代器种“自己”的数据,但这些都是拿C++的优势,提供一个神奇的功能神奇的特性,不是由C++定义的迭代器的固有属性。

2

迭代器是一般只要其原始唯一有效容器或“序列”尚未更改,因为更改可能会导致内存重新分配和内存移动。由于发起容器中的迭代器通常是参考内存,所以容器中的更改可能使迭代器无效。

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

1

首先,迭代器没有引用它迭代的对象的接口。它只实现指针语义,所以你可以把它看作抽象指针。当然,它的内部实现可能会持有指向该对象的指针,但在现实世界的实现中却不太可能。第二,当你的容器被销毁(当它超出范围时),容器中的所有对象也被销毁。因此,在容器被销毁后,迭代器将变为无效。在增加之后,递减和解引用迭代器将导致未定义的行为。