C ++:std :: vector中的push_back迭代它

时间:2016-03-11 10:52:38

标签: python c++ vector leaky-abstraction

以下代码段提供了一个非常奇怪的输出。我期待溢出(Python给出一个MemoryError)

#include <iostream>
#include <vector>

int main()
{
    std::vector<int> a{1,2,3};

    for( auto const & item : a)
        a.push_back(item);


    for( auto const & item : a)
        std::cout<<item<<',';

    return 0;
}

输出:1,2,3,1,0,3,

我如何解释这个结果?

如果你在Python中做了类似的事情,它会给出内存错误。

>>> a = range(0,20)
>>> for i in a:
    a.append(i)



Traceback (most recent call last):
  File "<pyshell#3>", line 2, in <module>
    a.append(i)
MemoryError

>>> 

我想到了这个问题,因为上面编写代码的方式被认为是绑定安全的。对于绑定的安全容器,foreach type iteration期间不应该增长/缩小。所以,这是一个漏洞的抽象。

是否有一种方法可以包装此foreach循环,以便在循环体中不允许任何导致大小修改/重新分配的操作。

2 个答案:

答案 0 :(得分:8)

在C ++中向向量添加元素可能会导致重新分配包含的数据,这将使所有迭代器无效。这意味着您不能使用迭代器(这是基于范围的for循环)循环遍历向量,同时还插入新元素。

可以但是使用索引进行迭代并使用向量大小作为条件,因为索引总是相同的。

答案 1 :(得分:3)

如果向量调整大小,迭代器将变为无效。

如果您提前预订,可以这样做。

请记住,for range将在进行任何更改之前对定义的迭代器边界进行操作。因此,只会附上您的清单副本。

#include <iostream>
#include <vector>

int main()
{
    std::vector<int> a{1,2,3};

    a.reserve(10);           // 10 should be enough to get a copy without reallocating
    for( auto const & item : a)
        a.push_back(item);

    for( auto const & item : a)
        std::cout<<item<<',';

    return 0;
}

输出:

1,2,3,1,2,3,

我不推荐这样的方法,因为我不认为它干净或清晰。但是,如果您参考标准,则会出现此行为:

  

23.3.6.5向量修饰符

关于insertemplaceemplace_backpush_back的使用。

  

备注:如果新大小大于旧容量,则会导致重新分配。如果没有重新分配,插入点之前的所有迭代器和引用仍然有效。

也就是说,如果没有重新分配,您可以在插入点之前信任迭代器。因此,只要矢量的容量足够高,就可以毫无问题地追加。