Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unexpected behavior using iterators with nested vectors

This sample program gets an iterator to an element of a vector contained in another vector. I add another element to the containing vector and then print out the value of the previously obtained iterator:

#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;
}

Since the vector correspinding to foo_it has not been modified I expect the iterator to still be valid. However when I run this code I get the following output (also on ideone):

*foo_it: 1
*foo_it: 0

For reference I get this result using g++ versions 4.2 and 4.6 as well as clang 3.1. However I get the expected output with g++ using -std=c++0x (ideone link) and also with clang when using both -std=c++0x and -stdlib=libc++.

Have I somehow invoked some undefined behavior here? If so is this now defined behavior C++11? Or is this simply a compiler/standard library bug?

Edit I can see now that in C++03 the iterators are invalidated since the vector's elements are copied on reallocation. However I would still like to know if this would be valid in C++11 (i.e. are the vector's elements guaranteed to be moved instead of copied, and will moving a vector not invalidate it's iterators).

like image 268
David Brown Avatar asked Dec 28 '22 01:12

David Brown


2 Answers

push_back invalidates iterators, simple as that.

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

After this, foo_ti is no longer valid. Any insert/push_back has the potential to internally re-allocate the vector.

like image 146
Luchian Grigore Avatar answered Dec 29 '22 14:12

Luchian Grigore


Since the vector correspinding to foo_it has not been modified

Wrong. The push_back destroyed the vector corresponding to foo_it. foo_it became invalid when foo[0] was destroyed.

like image 42
Robᵩ Avatar answered Dec 29 '22 15:12

Robᵩ