我使用了C++11标准提供的新的基于范围的for循环,并提出了以下问题:假设我们使用基于范围的for在vector<>上迭代,并在此迭代期间在向量的末尾添加一些元素。那么,循环什么时候结束呢?
例如,请参阅以下代码:
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<unsigned> test({1,2,3});
for(auto &num : test) {
cout << num << " ";
if(num % 2)
test.push_back(num + 10);
}
cout << "\n";
for(auto &num : test)
cout << num << " ";
return 0;
}我使用"-std=c++11“标志测试了G++ 4.8和Apple LLVM version4.2 (clang++),输出结果是(对于两者):
1 2 3
1 2 3 11 13请注意,第一个循环终止于原始向量的末尾,尽管我们在其中添加了其他元素。似乎for-range循环仅在开始时计算容器的结尾。实际上,这是range-for的正确行为吗?这是委员会指定的吗?我们可以信任这种行为吗?
请注意,如果我们将第一个循环更改为
for(vector<unsigned>::iterator it = test.begin(); it != test.end(); ++it)使用无效的迭代器,并提出分段错误。
发布于 2013-06-13 07:02:24
不,你不能依赖这种行为。修改循环中的向量会导致未定义的行为,因为当修改向量时,循环使用的迭代器将无效。
基于范围的for循环
for ( range_declaration : range_expression) loop_statement本质上等同于
{
auto && __range = range_expression ;
for (auto __begin = std::begin(__range),
__end = std::end(__range);
__begin != __end; ++__begin) {
range_declaration = *__begin;
loop_statement
}
}修改向量时,迭代器__begin和__end不再有效,取消引用__begin会导致未定义的行为。
发布于 2016-02-18 05:10:33
只要向量的容量足够大,您就可以依赖此行为,因此不需要重新分配。这将保证所有迭代器和引用的有效性,而不是在调用push_back()之后的结束迭代器。这很好,因为end()在循环开始时只计算了一次(参见std::vector::push_back)。
在您的示例中,您必须增加test向量的容量以保证此行为:
vector<unsigned> test({1,2,3});
test.reserve(5);编辑
根据对Is it legal to add elements to a preallocated vector in a range-based for loop over that vector?的响应,这是一种未定义的行为。使用gcc、clang和cl构建的发布版本运行良好,但使用cl (Visual Studio)构建的调试版本将抛出异常。
https://stackoverflow.com/questions/17076672
复制相似问题