Reputation: 12552
How can I safely design a move constructor when a class uses multiple inheritance?
Consider the following scenario:
struct T { };
struct U { };
struct X : public T, public U
{
X(X&& other)
: T(std::move(other))
, U(std::move(other)) // already moved?!
{
}
};
Is there a way to move-construct both T
and U
safely?
Upvotes: 18
Views: 2558
Reputation: 61
Can I use other object in sidetone constructor body after using moving it like:
struct T { };
struct U { };
struct X : public T, public U
{
X(X&& other)
: T(std::move(other))
, U(std::move(other)) // already moved?!
{
member1 = other.member1; //something like.
}
};
Upvotes: 1
Reputation:
The code in the question is fine, as the answer from @je4d explained it.
You could also write it this way :
X(X&& other)
: T(static_cast<T&&>(other))
, U(static_cast<T&&>(other))
{
}
See the comment of the answer from @jead for explanation.
Upvotes: 0
Reputation: 7838
tl;dr: the code in the question is ok.
The code above is fine, because std::move
itself doesn't actually change other
in any way, it just does a cast to make other
into an rvalue reference so that the move constructors of T
and U
are called instead of their copy constructors.
When T(std::move(other))
is run, T
's move constructor will be called (assuming it has one) and the T
in other
will be moved to the T
in this
. The U
in other
will be left alone until the U(std::move(other))
is run.
Note that this means that when your move constructor code for X
runs, you cannot rely on the members/member functions of T
and U
in other
, as those bits of other
will have already have been moved.
As a side note, it could be improved by being changed to:
X(X&& other)
: T(std::move(static_cast<T&>(other)))
, U(std::move(static_cast<U&>(other)))
{
}
because this version doesn't rely on the implicit upcast from X&&
to T&&
/U&&
. Relying on the implicit upcast can be a problem because T
and/or U
may have a T(X&&)
constructor or an accept-anything template constructor, either of which would get picked instead of the T(T&&)
move constructor that you really want to call.
Upvotes: 18