2012-04-29 19 views
4

此示例程序获取迭代器到包含在另一个向量中的向量的元素。添加其他元素添加到含有载体,然后打印出先前获得的迭代器的值:使用带有嵌套向量的迭代器的意外行为

#include <vector> 
#include <iostream> 

int main(int argc, char const *argv[]) 
{ 
    std::vector<std::vector<int> > foo(3, std::vector<int>(3, 1)); 
    std::vector<int>::iterator foo_it = foo[0].begin(); 
    std::cout << "*foo_it: " << *foo_it << std::endl; 
    foo.push_back(std::vector<int>(3, 2)); 
    std::cout << "*foo_it: " << *foo_it << std::endl; 
    return 0; 
} 

由于correspinding到foo_it矢量没有被修改我期望迭代器仍然是有效的。然而,当运行此代码我得到(还ideone)下面的输出:

*foo_it: 1 
*foo_it: 0 

为了参考我使用的g ++版本4.2和4.6以及3.1铛得到这样的结果。然而,当使用-std=c++0x-stdlib=libc++时,我用g ++使用-std=c++0xideone link)以及clang得到预期的输出。

我有办法在这里调用一些未定义的行为吗?如果是这样,现在定义的行为C++ 11?或者这只是一个编译器/标准库错误?

编辑我现在可以看到,在C++ 03中迭代器被无效,因为向量的元素在重新分配时被复制。然而,我仍然想知道这是否在C++ 11中有效(即矢量的元素是否保证被移动而不是被复制,并且移动矢量不会使其迭代器失效)。

回答

5

push_back使迭代器失效,就像那样简单。

std::vector<int>::iterator foo_it = foo[0].begin(); 
foo.push_back(std::vector<int>(3, 2)); 

在此之后,foo_ti不再有效。任何insert/push_back都有可能在内部重新分配向量。

+0

并且还使向量元素的任何指针或引用无效,例如'operator []'获得的元素。 – 2012-04-29 00:36:43

+0

他没有在'vector'上调用'push_back',他从中获得迭代器。 – 2012-04-29 00:36:43

+0

@LuchianGrigore他调用'foo [0] .begin()',然后''push_back'在'foo'上,而不是'foo [0]' – 2012-04-29 00:38:08

5

由于correspinding到foo_it矢量没有被修改

错误。 push_back销毁了对应于foo_it的向量。当foo[0]被销毁时,foo_it无效。

0

我猜误解是矢量< vector < int>>是一个指针的向量,当外部函数被重新分配时,指向内部函数的指针仍然有效,这对** int是正确的。但是,重新分配矢量也会重新分配所有内部矢量,这也会使内部迭代器无效。

+0

并非总是如此。 (事实上​​,在C++ 11中总是假的) – 2012-04-29 01:38:51

+0

我通过打印出两个值的地址来测试它,它们是相同的。这意味着来自内部向量的数据已被重新分配,对吗? – guinny 2012-04-29 01:44:37

+0

这取决于你在说什么地址。尽管如此,在C++ 11中,std :: vector必须在可能的情况下移动它的内部(而不是复制),移动操作不会使迭代器失效或导致重新分配。 – 2012-04-29 02:13:09