2009-11-26 53 views
0

这是一个问题,去BOOST_FOREACH怎么检查它的循环终止修改向量的内容BOOST_FOREACH

cout << "Testing BOOST_FOREACH" << endl; 
vector<int> numbers; numbers.reserve(8); 
numbers.push_back(1); numbers.push_back(2); numbers.push_back(3); 
cout << "capacity = " << numbers.capacity() << endl; 
BOOST_FOREACH(int elem, numbers) 
{ 
    cout << elem << endl; 
    if (elem == 2) numbers.push_back(4); 
} 
cout << "capacity = " << numbers.capacity() << endl; 

使输出

Testing BOOST_FOREACH 
capacity = 8 
1 
2 
3 
capacity = 8 

可是你知道这是插入一半的4号通过循环?如果我将类型更改为列表,则新插入的数字将被迭代。如果需要重新分配,则向量push_back操作将使任何指针无效,但在本示例中不会发生这种情况。所以我想这个问题是为什么end()迭代器在使用vector时似乎只被评估过一次(在循环之前),但在使用列表时有更多的动态评估?

+0

我得到了一个运行代码的断言,Visual Studio 2008。 – GManNickG 2009-11-26 02:43:07

+0

@Gman:为了使它在Visual Studio 2008下工作,必须禁用迭代器调试('/ D_HAS_ITERATOR_DEBUGGING = 0')。 – 2009-11-26 02:46:09

+0

这不就是击败目的吗?你正在做一些未定义的行为之地。 **修正警告,不要让它们沉默。**这就好像有一个编译器在你超出数组界限时警告你,但是你禁用了它,所以你可以这样做。 – GManNickG 2009-11-26 02:50:09

回答

6

下面,BOOST_FOREACH使用 迭代器遍历元素 序列。在循环执行之前, 结束迭代器被缓存在本地 变量中。这就是所谓的吊装,而且这是一个重要的优化。但是,它假定序列的迭代器的末端 是稳定的。它通常是 ,但如果我们通过添加或删除 元素来修改 序列,而我们正在迭代 它,我们可能最终会在我们自己的屁股上提升自己 。

http://www.boost.org/doc/libs/1_40_0/doc/html/foreach/pitfalls.html

如果你不想结束()迭代改变使用的载体,而不是储备调整。

http://www.cplusplus.com/reference/stl/vector/resize/

注意,那么你就不会想的push_back但使用操作符[]来代替。但要小心超出界限。当它的迭代器

+0

这不是他的问题。 – GManNickG 2009-11-26 02:45:12

+0

对不起,以为他在问为什么大小没有改变=) 改变我的答案=) – Eld 2009-11-26 02:51:49

+0

从同一链接: 故事的寓意是在添加和删除序列中的元素正在迭代。如果这样做可能导致迭代器失效,请不要这样做。改为使用常规循环。 – 2009-11-26 02:57:46

0

升压转换器的的foreach将终止== numbers.end()

不过要小心,调用的push_back能/会作废您有任何当前迭代器。

+0

不是任何,只有那些插入后,除非载体增长超过其容量()'(并注意他如何使用'reserve()')。 – 2009-11-26 17:21:44

2

在评论中提出了一个问题,为什么Microsoft调试运行时会在迭代过程中引发断言,而不是在列表上。原因是insert的定义与listvector不同(注意push_back只是序列末尾的insert)。

每C++标准(ISO/IEC 14882:2003 23.2.4.3,矢量改性剂):

[在插入],如果没有重新分配发生,所有的迭代器和引用插入点之前保持有效。

(23.2.2.3,列表修饰符):

[插入],不影响迭代器和引用的有效性。

所以,如果你使用push_back(并确保它不会导致重新分配),也没关系与任何容器继续使用迭代器来遍历序列的其余部分。

在载体的情况下,但是,它的未定义行为使用您的push_back之前获得的end迭代器。

这是一个回旋的问题;这是对问题评论中讨论的直接回答。