2

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.

francesco
  • 7,189
  • 7
  • 22
  • 49
  • 3
    There is no [object slicing](https://stackoverflow.com/questions/274626/) occurring in the code shown. Just references to different areas of the same object being passed around. And yes, if you `move()` only a portion of an object, other portions remain in their original state. A move does not invalidate an object itself, only its content. – Remy Lebeau Apr 21 '21 at 20:51
  • 1
    Object after move is in valid & undefined state. Using such object isn't UB. E.g. for vector you can call clear, and use this object again. – AdamF Apr 21 '21 at 20:58

0 Answers0