This is the move constructor of class X
:
X::X(X&& rhs)
: base1(std::move(rhs))
, base2(std::move(rhs))
, mbr1(std::move(rhs.mbr1))
, mbr2(std::move(rhs.mbr2))
{ }
These are the things I'm wary about:
- We're moving from
rhs
twice andrhs
isn't guaranteed to be in a valid state. Isn't that undefined behavior for the initialization ofbase2
? - We're moving the corresponding members of
rhs
tombr1
andmbr2
but sincerhs
was already moved from (and again, it's not guaranteed to be in a valid state) why should this work?
This isn't my code. I found it on a site. Is this move constructor safe? And if so, how?
Best Answer
This is approximately how an implicit move constructor typically works: each base and member subobject is move-constructed from the corresponding subobject of
rhs
.Assuming that
base1
andbase2
are bases ofX
that do not have constructors takingX
/X&
/X&&
/const X&
, it's safe as written.std::move(rhs)
will implicitly convert tobase1&&
(respectivelybase2&&
) when passed to the base class initializers.EDIT: The assumption has actually bitten me a couple of times when I had a template constructor in a base class that exactly matched
X&&
. It would be safer (albeit incredibly pedantic) to perform the conversions explicitly:or even just:
which I believe should exactly replicate what the compiler would generate implicitly for
X(X&&) = default;
if there are no other base classes or members thanbase1
/base2
/mbr1
/mbr2
.EDIT AGAIN: C++11 ยง12.8/15 describes the exact structure of the implicit member-wise copy/move constructors.