7

以下代码片段提供了一个非常奇怪的输出。我期待一个溢出(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循环,以便在循环体中不允许任何导致大小修改/重新分配的操作。

4

2 回答 2

16

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

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

于 2016-03-11T10:57:18.397 回答
5

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

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

请记住,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 矢量修饰符

关于insert, emplace, emplace_back,的使用push_back

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

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

于 2016-03-11T11:02:40.773 回答