class MyClass
{
private:
int x;
public:
MyClass(int x)
{
this->x = x;
}
MyClass(const MyClass& other)
{
this->x = other.x;
}
};
int main()
{
MyClass first(1);
MyClass second = first; //(1)
first = second; // (2)
MyClass third = MyClass(2); // (3)
}
Why the first line MyClass second = first
calls the copy constructor and the second first = second;
calls the assignment operator, and why the third MyClass third = MyClass(2);
did not act like line one by calling the copy constructor.
Finlly, what exactly line 3 do MyClass third = MyClass(2);
.
Constructors, including copy constructors, are for initializing a class object. Assignment operators are for modifying an object which was already initialized.
Line (1) calls a copy constructor because it is initializing the object second
. The assignment operator has nothing to do with the fact that the =
symbol is also used in this syntax. Line (2) assigns to first
which already exists, so uses the assignment operator.
In C++14 and earlier for line (3), the compiler is allowed to create a temporary object for the MyClass(2)
expression, then use the copy constructor to initialize third
, then destroy the temporary. But the compiler is also allowed to "elide" (remove) the temporary object, the copy constructor, and the temporary destructor, just initializing third
directly in the same way as the original temporary. This copy elision is the one case where C++ allows an optimization which can cause a difference in observable behavior, since the copy constructor and/or destructor might have side effects (like printing traces) which the optimization skips.
In C++17 and later for line (3), we say that the expression MyClass(2)
has result object third
. So the expression specifies that third
is direct-initialized with argument 2
. No copy constructor or temporary object is involved. This feature of C++17 is often called "mandatory copy elision", since the behavior is the same as a C++14 program where the compiler was able to apply the copy elision optimization. But technically it's not a copy elision, since there is no copy involved to elide. There are still some other cases where copy elision is optional for the compiler.