When a variable is passed as xvalue to a move constructor, one should assume that after execution the variable is in a "undefined" state; using it afterwards would incur in UB. However, what will happen if an xvalue is "sliced" by (implicitly or explicitly) casting it to a base class? Would the variable still be partially "usable"?
Example:
#include <vector>
struct inA {
std::vector<int> s;
};
struct A {
std::vector<int> s;
A(inA&& x) : s(std::move(x.s)) { }
};
struct inB : public inA {
std::vector<char> t;
};
struct B : public A {
std::vector<char> t;
B(inB&& x) : A(std::move(x)), t(std::move(x.t)) { }
};
int main()
{
inB v{std::vector<int>(3, 1), std::vector<char>(5, 'a')};
B w(std::move(v));
return 0;
}
(I use std::vector
to have a non-trivial move constructor).
The constructor of A
accepts a moving reference to a inA
object. After that the moved inA
object is in a undefined state and cannot be used:
std::vector<int> vec{3, 10};
A a(std::move(vec));
// vec[0] = 2; // UB!!
So far, so good.
Now, the constructor of B
can accept a moving reference to a inB
object, which is derived from inA
.
By inheritance, the B::B
forward the "slice" of inB&& x
pertaining to the inA
to the constructor of the base class A
. Then B::B
initializes a member variable with the part of inB
which was not inherited from inA
.
Is this last step (i.e. t(std::move(x.t))
) allowed?
On one hand, x
has been already forwarded as moving reference to A::A
, so it would be in a undefined state and using it afterwards incurs into UB.
On the other hand, A::A
cannot touch the member variable inB::t
because, due to slicing, it simply does not see it. So I would conclude that inB::t
is still usable.