以下代码段提供了一个非常奇怪的输出。我期待溢出(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
循环,以便在循环体中不允许任何导致大小修改/重新分配的操作。
答案 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向量修饰符
关于insert
,emplace
,emplace_back
,push_back
的使用。
备注:如果新大小大于旧容量,则会导致重新分配。如果没有重新分配,插入点之前的所有迭代器和引用仍然有效。
也就是说,如果没有重新分配,您可以在插入点之前信任迭代器。因此,只要矢量的容量足够高,就可以毫无问题地追加。