Initializing base with rvalue reference of derived

Viewed 79

In the following code:

struct A {
    A() {}
    A(A &&) { printf("moving A\n"); }
    ~A() { printf("destructing A\n"); }
};

struct B : A {
    B() {}
    B(B &&) { printf("moving B\n"); }
    ~B() { printf("destructing B\n"); }
};

B func() {
    B b;
    return b;
}

int main() {
    A a = func();
    printf("hello\n");
}

The following output is produced:

moving A
destructing B
destructing A
hello
destructing A

Why isn't the move elided? Why is the move constructor of A called but not that of B? What's actually happening here?

1 Answers

Why is the move constructor of A called but not that of B?

Because you're constructing an A, then only A's constructors will be considered. Particularly, the temporary B returned by func() could bind to A&&, then A's move constructor is used to construct a; in ohter word, a is sliced from the temporary B.

Why isn't the move elided?

Copy elision is not allowed for this case, a has to be constructed from the temparary B.

First, if T is a class type and the initializer is a prvalue expression whose cv-unqualified type is the same class as T, the initializer expression itself, rather than a temporary materialized from it, is used to initialize the destination object: see copy elision

func() returns a B, which is not the same type as A exactly.

Related