Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why this move constructor is not called wtih rvalue temporary? [duplicate]

class MyClass
{
public:
  ~MyClass() {}
  MyClass():x(0), y(0){} //default constructor
  MyClass(int X, int Y):x(X), y(Y){} //user-defined constructor
  MyClass(const MyClass& tempObj):x(tempObj.x), y(tempObj.y){} //copy constructor

private:
  int x; int y;
};

int main()
{
  MyClass MyObj(MyClass(1, 2)); //user-defined constructor was called.
  MyClass MyObj2(MyObj); //copy constructor was called.
}

In the first case, when MyClass(1, 2) calls the user-defined constructor and returns an object, I was expecting MyObj to call the copy constructor. Why it doesn't need to call the copy constructor for the second instance of MyClass?

like image 871
cpx Avatar asked Nov 18 '22 00:11

cpx


2 Answers

Whenever a temporary object is created for the sole purpose of being copied and subsequently destroyed, the compiler is allowed to remove the temporary object entirely and construct the result directly in the recipient (i.e. directly in the object that is supposed to receive the copy). In your case

MyClass MyObj(MyClass(1, 2));

can be transformed into

MyClass MyObj(1, 2);

even if the copy constructor has side-effects.

This process is called elision of copy operation. It is described in 12.8/15 in the language standard.

like image 127
AnT Avatar answered Feb 08 '23 23:02

AnT


The copy constructor may be elided in such a case.

Likewise with MyClass MyObj = MyClass( 1, 2 );.

And with

std::string str = "hello";

Such code has an implicit constructor call to convert the char* to a std::string.

std::string str = std::string( "hello" ); // same, written more verbosely

Without copy elision, the "easy" string initialization by assignment syntax would incur an additional deep copy. And that syntax is 99% equivalent to what you have.

like image 34
Potatoswatter Avatar answered Feb 09 '23 00:02

Potatoswatter