Synopsis
How can I safely design a move constructor when a class uses multiple inheritance?
Details
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?
tl;dr: the code in the question is ok.
The code above is fine, because
std::moveitself doesn’t actually changeotherin any way, it just does a cast to makeotherinto an rvalue reference so that the move constructors ofTandUare 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 theTinotherwill be moved to theTinthis. TheUinotherwill be left alone until theU(std::move(other))is run.Note that this means that when your move constructor code for
Xruns, you cannot rely on the members/member functions ofTandUinother, as those bits ofotherwill have already have been moved.As a side note, it could be improved by being changed to:
because this version doesn’t rely on the implicit upcast from
X&&toT&&/U&&. Relying on the implicit upcast can be a problem becauseTand/orUmay have aT(X&&)constructor or an accept-anything template constructor, either of which would get picked instead of theT(T&&)move constructor that you really want to call.