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

jha*_*a-G 5 c++ python 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;
}
Run Code Online (Sandbox Code Playgroud)

产量: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

>>> 
Run Code Online (Sandbox Code Playgroud)

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

有没有办法可以包装这个foreach循环,以便在循环体中不允许任何导致大小修改/重新分配的操作.

Som*_*ude 10

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

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


Jua*_*eni 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;
}
Run Code Online (Sandbox Code Playgroud)

输出:

1,2,3,1,2,3,
Run Code Online (Sandbox Code Playgroud)

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

23.3.6.5向量修饰符

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

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

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