Assume there is a class A that contains a vector of ints. Now assume that a vector of A\'s is created. If a reallocation of an A object occurs (so the vector object is moved) du
Your A
elements will be moved where possible, and A
has an implicit move constructor and implicit move assignment operator, so the member vector will also be moved.
Now, moving a vector is not necessarily equivalent to a.swap(b)
, so you cannot rely on the implicit move functions if you want a guarantee; you could write your own.
But whether you guarantee it yourself or obtain a guarantee by looking up the code of your particular standard library implementation, you can be assured that pointers and iterators to the individual elements shall remain valid:
[C++11: 23.2.1/8]:
The expressiona.swap(b)
, for containersa
andb
of a standard container type other thanarray
, shall exchange the values ofa
andb
without invoking any move, copy, or swap operations on the individual container elements. [..]
It would depend of your move constructor of A
.
but as it (*), it will use move constructor of vector<int>
for a
, and according to http://www.cplusplus.com/reference/vector/vector/vector/
[..] no elements are constructed (their ownership is directly transferred).
So pointers to the ints themselves remain valid.
Edit: (*) A
should be noexcept
for that, and std::vector
is not guaranteed to be noexcept
.
Unfortunately this is not guaranteed. That being said, it is the case that all 3 current implementations (libc++, libstdc++ and VS-2015) appear to guarantee it. The question is whether or not the move constructor for A
is noexcept:
static_assert(std::is_nothrow_move_constructible<A>::value, "");
The move constructor for A
is compiler supplied, and thus dependent upon the move constructor of std::vector<int>
. If the move constructor of std::vector<int>
is noexcept, then the move constructor for A
is noexcept, else it is not.
The current draft N4296 does not mark the move constructor for vector
as noexcept. However it allows implementations to do so.
This line:
aVec.resize(30);
Will use A
's move constructor if that move constructor is noexcept, else it will use A
's copy constructor. If it uses A
's copy constructor, the location of the ints will change. If it uses A
's move constructor, the location of the ints will remain stable.
libc++ and libstdc++ mark vector
's move constructor as noexcept. And thus give A
a noexcept move constructor.
VS-2015 says that A
does not have a noexcept move constructor:
static_assert(std::is_nothrow_move_constructible<A>::value, "");
does not compile.
Nevertheless, VS-2015 does not reallocate the ints to a new address, and thus it looks like it is not conforming to the C++11 spec.
If one changes the libc++ headers such that the vector
move constructor is not marked noexcept, then the ints do indeed reallocate.
Recent discussions on the committee indicate that everyone is in favor of marking the move constructor of vector
noexcept (and maybe basic_string
too, but not other containers). So it is possible that a future standard will guarantee the stability you seek. In the meantime, if:
static_assert(std::is_nothrow_move_constructible<A>::value, "");
compiles, then you have your guarantee, else you don't.
Update
The reason that x2 != y2
in the update is that these are the addresses of vector<int>
in the vector<vector<int>>
. These inner elements had to find a new (bigger) buffer to live in, just the same as if the inner element was int
. But unlike int
, the inner element vector<int>
could move there with a move constructor (int
had to copy). But whether moving or copying, the address of the inner element had to change (from the small old buffer to the big new buffer). This behavior is consistent with the original part of the question (where the inner element is also shown to change addresses).
And yes, LWG 2321 is involved, though not a contentious point. In my answer I've already assumed LWG 2321 has passed. There's really no other way for things to happen aside from overly eager debugging iterators to gratuitously (and incorrectly) invalidate themselves. Non-debugging iterators would never invalidate, and neither will pointers or references.
Wish I had the ability to easily create an animation with arrows to buffers. That would be really clear. I just don't know how to easily do that in the time I have available.