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
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::value, "");
The move constructor for A
is compiler supplied, and thus dependent upon the move constructor of std::vector
. If the move constructor of std::vector
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::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::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
in the vector
. 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
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.