Here is some basic C++ outline of code:
#include <cstdlib>
#include <iostream>
#include <thread>
using namespace std;
class M {
public:
M() = default;
~M() {
cout << "Called ~M" << endl;
}
};
class A {
public:
A(int z) : _z(z) {
cout << "Called A(int z)" << endl;
this_thread::sleep_for(chrono::milliseconds(1000));
}
A() {
cout << "Called A()" << endl;
this_thread::sleep_for(chrono::milliseconds(1000));
}
A(const A& a) {
cout << "Called A(const A& a)" << endl;
_z = a._z;
}
A(const A&& a) {
cout << "Called A(const A&& a)" << endl;
_z = a._z;
}
A& operator=(const A& a) {
cout << "Called A& operator=(const A& a)" << endl;
if (&a != this) {
cout << "Executed A& operator=(const A& a)" << endl;
}
}
virtual ~A() {
cout << "Called ~A" << endl;
}
int poll() const { return _z; }
private:
M _m;
int _z = 300;
};
class B : public A {
public:
// _a(10)
B() : _a(std::move(A(10))) {
cout << "Called B()" << endl;
}
virtual ~B() {
cout << "Called ~B" << endl;
}
private:
const A& _a;
};
int main(int argc, char** argv) {
B b;
A* aPtr = &b;
A& aRef = (*aPtr);
cout << aRef.poll() << endl;
return 0;
}
from the setup above I get the following output:
Called A()
Called A(int z)
Called ~A
Called ~M
Called B()
300
Called ~B
Called ~A
Called ~M
My issue is the first line of the output (all the others make sense given the first). I am initializing the member _a
in B() : _a(std::move(A(10)))
, this is forced as _a
is const reference member. And the CTOR with int argument gets called as well, however why is the default CTOR called on A? Why no move CTOR? Therefore the temporary object simply seems constructed and destroyed, no real move is happening (as can be seen from the 300 output later on).
Now this issue does not seem related to the move per se but to the behaviour around the const reference member. Because if I change the initialization list to: B(): _a(10)
I get the same issue: somehow the default object is assigned to the const reference member and the arguments in the initialization list are ignored. So for B(): _a(10)
I get:
Called A()
Called A(int z)
Called B()
300
Called ~B
Called ~A
Called ~M
Basically why is the first line a default constructor? And how do I alter the code so that the 10 from the initialization appears instead of the 300 from the default?
Each object of type B has actually two subobjects of type A. One is the base-class subobject, and the other is the _a
member subobject. You call the constructor for the member, but the base-class subobject is default-initialized since you haven't explicitly called its constructor in your initialization list.
You could do it by, for example, the following:
B() : A(arguments) //<--initialize the base-class subobject
, _a(std::move(A(10))) {
cout << "Called B()" << endl;
}