Reputation: 16242
I am trying to understand the generic rules of move semantics. Specifically of containers and contained elements.
The reason is that I am trying to understand move in the context of ownership and iterator invalidation.
To do that I am going through some cases with increasing complexity involving a typical container, a general contained type T
, general g
and f
functions.
(Maybe an important extra detail is that f
might or might not actually do a move operation, or it could be contingent at runtime.)
The idea is to introduce Case 3 which is the core of this question.
First a fairly uncontroversial case, this is ok:
std::vector<T> v(100, t);
f(std::move(v));
v = make_a_vector();
However, use-after-move is likely smelly code
std::vector<T> v(100, t);
f(std::move(v));
g(v);
I think most people agree that this above is not ok.
The rule being (as far I know) that the only operation after move should be assignment.
I think this is particularly because it is undocumented (undefined but valid state) what is the state of a moved-from vector, (or even if it was moved at all.).
So, at best v
is empty and at worst v
is an unspecified state and therefore g
could do something unspecified in this scope.
std::vector<T> v(100, t);
f(std::move(v));
v.resize(120);
Is it correct?
It is not an assignment, but resize
has no preconditions. (found this Can I resize a vector that was moved from?)
Now the really tricky case.
std::vector<T> v(100);
h(std::make_move_iterator(v.begin()), std::make_move_iterator(v.end()));
v.resize(120);
(Here, h
is a function that takes iterators, assume that implicitly it refers to the range [iterator1, iterator2)
.)
Is this correct code?
The reason is that .resize
seems to be going to play, move, swap and copy moved-from object of type T
.
To summarize, is it correct to resize a vector whose elements have been (possibly) moved-from?
EDIT: For the sake of argument, let's specify the signatures of the functions in case they are relevant to the answer(s):
template<class T> void f(std::vector<T>&&);
template<class T> void g(std::vector<T> const&);
template<class It> void h(It first, It last);
Upvotes: 1
Views: 131
Reputation: 217283
std::vector<T> v(100, t);
f(std::move(v));
v.resize(120);
is similar to your case 1
std::vector<T> v(100, t);
f(std::move(v));
g(v);
vector::resize
has no prerequires, but you don't know previous state.
it might be empty, have some size (with unspecified value).
So after v.resize(120)
, you just know that the new size is 120
, but doesn't know its contents (new elements are default constructed, but which are they?).
Upvotes: 1
Reputation: 141586
If it's a vector of standard-library objects, then it is guaranteed to be safe to resize the vector. See What constitutes a valid state for a "moved from" object in C++11? .
If a vector of your own objects -- then the question comes back to whether you designed your own objects to be valid once moved from.
Upvotes: 5