列出迭代器与矢量迭代器

时间:2013-12-24 20:39:13

标签: c++ stl iterator stdvector stdlist

我有两个关于迭代器的问题。

  1. 我认为一旦你定义了一个STL容器的迭代器,例如向量或列表,如果你向容器添加元素,那么这些迭代器将无法访问它们。但是下面的代码定义了五个元素的列表,然后在每个循环迭代中添加另一个元素并导致无限循环:

    #include <iostream>
    #include <list>
    
    using namespace std;
    
    int main()
    {
        list<int> ls;
    
        for(int i = 0; i < 5; i++)
        {
            ls.push_back(i);
        }
    
        int idx = 0;
    
        for(list<int>::iterator iter = ls.begin(); iter != ls.end(); iter++)
        {
            cout << "idx: " << idx << ", *iter: " << *iter << endl;
            ls.push_back(7);
            idx++;
        }
    }
    

    但是,对矢量执行相同操作会导致错误:

    #include <iostream>
    #include <vector>
    
    using namespace std;
    
    int main()
    {
        vector<int> vec;
    
        for(int i = 0; i < 5; i++)
        {
            vec.push_back(i);
        }
    
        int idx = 0;
    
        for(vector<int>::iterator iter = vec.begin(); iter != vec.end(); iter++)
        {
            cout << "idx: " << idx << ", *iter: " << *iter << endl;
            vec.push_back(7);
            idx++;
        }
    }
    
  2. 我认为当向量容器必须调整大小时,它会以2的幂为单位并且位于新的内存区域,这就是为什么在添加时不应该为向量定义迭代器的原因它的元素(因为迭代器不会传递到新的内存位置)。例如,我认为在调用push_back函数之后,包含16个元素的向量将被分配32个元素的空间,并且将重新定位整个向量。但是,以下代码没有发生这种情况。我错了吗?

    #include <iostream>
    #include <vector>
    
    using namespace std;
    
    int main()
    {
        vector<int> vec;
    
        for(int i = 0; i < 4; i++)
        {
            vec.push_back(i);
            cout << "address of vec: " << &vec << ", capacity: " << vec.capacity() << endl;
        }
    
    
    
        for(int i = 0; i < 20; i++)
        {
            vec.push_back(i);
            cout << "address of vec: " << &vec << ", capacity: " << vec.capacity() << endl;
        }
    }
    

3 个答案:

答案 0 :(得分:3)

不同容器的迭代器具有不同的属性。 Here are the iterator invalidation rules

列表循环:当您按下list时,所有以前的迭代器仍然有效。如果你每次迭代前进一个,你也永远不会达到目的,显然你也会添加一个新元素。

向量循环:对于向量,一旦push_back导致新大小超过旧容量,则迭代器无效。一旦发生这种情况,使用iter是未定义的行为(您可能会崩溃)。

  

我认为当必须调整矢量容器大小时,它会这样做   在2的幂,并位于一个新的记忆区域

标准未指明。当大小超过旧容量时,C ++标准库的某些实现会使向量的容量加倍,而其他实现则以不同的速率增长。

答案 1 :(得分:0)

第一个问题的答案包含在你的第二个问题中。

至于第二个问题,那么实现定义了向量如何分配内存。每次耗尽时,没有必要将内存的大小加倍。

答案 2 :(得分:0)

对于迭代器的有效性以及对元素的指针/引用,不同的容器通常有不同的保证:

  1. 对于std::list<T>,元素的迭代器和指针/引用保持有效,直到相应的节点被删除或std::list<T>存在。
  2. 对于std::vector<T>,有效性更复杂:
    1. 迭代器和指针/引用有效性是相同的(我将只使用下面的迭代器)。
    2. std::vector<T>需要调整其内部缓冲区大小时,即插入超出容量时,所有迭代器都无效。当超出容量并分配多少内存取决于实现(唯一的要求是容量呈指数级增长,2倍是合理的选择,但还有很多其他选择)。
    3. 在插入点之前插入std::vector<T>所有迭代器时保持有效,除非需要重新分配。
    4. 当擦除std::vector<T>擦除点之后的所有迭代器时无效。
  3. 其他容器有不同的有效性约束(例如std::deque<T>使迭代器无效,但可以使指针/引用保持有效)。