I'm studying C++ and created this simple code to practice copy constructors.
class Cube{
private:
double length;
public:
Cube(){
length = 1;
cout << "default constructor called" << endl;
};
Cube(const Cube& obj){
length = obj.length;
cout << "copy constructor called" << endl;
};
};
Cube foo(){
Cube c;
return c;
}
int main(){
Cube c2 = foo();
return 0;
}
I expected this to print
"default constructor called"
"copy constructor called"
"copy constructor called"
as default constructor is called in "Cube C", and copy constructor is called in "return c" and "Cube c2 = foo()".
However my console only shows "default constructor called"
Am I misunderstanding on how copy constructor works?
This won't call your copy constructor, instead what happens is that the created object in foo gets initialized to c2.
Cube c2 = foo();
This will call the = assignment operator:
Cube c2; // default constructor
c2 = foo(); // default constructor inside foo() and then assignment operator
This will call the copy constructor:
Cube c3; // default constructor
Cube c2(c3); // copy constructor
The copy constructor has the syntax:
Cube(const Cube& obj)
It is a constructor that creates a copy of an object from another object.
However my console only shows "default constructor called"
Because of copy elision.
Your expectations are right. There're two copy constructions in concept, the 1st one is for return c;, copy-initialize the return value from c; the 2nd one is for Cube c2 = foo();, copy-initialize c2 from the return value of foo(). They're both omitted because of copy elision then the copy constructor is not called at all.
For the 1st one,
In a return statement, when the operand is the name of a non-volatile object with automatic storage duration, which isn't a function parameter or a catch clause parameter, and which is of the same class type (ignoring cv-qualification) as the function return type. This variant of copy elision is known as NRVO, "named return value optimization".
For the 2nd one,
In the initialization of an object, when the initializer expression is a prvalue of the same class type (ignoring cv-qualification) as the variable type:
T x = T(T(f())); // only one call to default constructor of T, to initialize x
Note that the 2nd one is mandatory since C++17.
BTW: Compiling in pre-C++17 mode (to avoid mandatory copy elision) with -fno-elide-constructors option (to avoid potential copy elision) gives the result you expected. LIVE with gcc
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With