2

I create a class A, and overwrite operator+ and constructor A(A&&), I am wondering if I call

A a, b;
A c = a + b;

Is my constructor A(A &&) called?

I tried some code, but get very confusing results

//try2.cpp

#include <iostream>
#include <string>
using namespace std;
class A {
public:
  string s;
  A(A &&a) { s=std::move(a.s); cout<<"A(A &&a) called"<<endl;}
  A() {}
};

A operator+(const A &a, const A &b) {
  A c;
  c.s=a.s+b.s;
  return c;
}

int main() {
  A a,b;
  a.s = "123";
  b.s = "456";
  A c = a+b;
  cout<<c.s<<endl;
  return 0;
}

I used gcc 7.0: g++ -std=c++1y try2.cpp

Output is 123456, therefore A(A &&a) is not called

But then I change

A(A &&a) = delete;

Then compiler throws error:

try2.cpp: In function ‘A operator+(const A&, const A&)’:
try2.cpp:14:10: error: use of deleted function ‘A::A(A&&)’
   return c;
          ^
try2.cpp:7:3: note: declared here
   A(A &&a) = delete;
   ^
try2.cpp: In function ‘int main()’:
try2.cpp:21:11: error: use of deleted function ‘A::A(A&&)’
   A c = a+b;
           ^
try2.cpp:7:3: note: declared here
   A(A &&a) = delete;

Constructor A(A &&a) is required. But why the previous code did not call it?

Xian Qian
  • 21
  • 1
  • 2
    Relevant [Copy elision question](https://stackoverflow.com/questions/12953127/what-are-copy-elision-and-return-value-optimization) – Quimby May 05 '19 at 17:55

2 Answers2

1

Named Return Value Optimization.

The compiler realized that, instead of creating an A in the scope of operator+ and moving it out of operator+ and into main, it could (basically) just construct it in main and have operator+ work on the value that's in main.

In order for your program to be valid, you need some constructor that lets the value be copied -- but the compiler need not use it, if it realizes it can optimize away some copies / moves.

druckermanly
  • 2,694
  • 15
  • 27
1

What is happening here is copy elision. Your move constructor is not being called, because the compiler has the option to construct your object 'c', which is being used inside your operator+ function, straight to the object 'c' at the call site. This is an optional optimization that avoids that extra move (or copy) constructor.

You run into a compilation error when explicitly deleting the move constructor, because this is an optional optimization by the compiler. The compiler is still allowed to call a copy/move constructor if it wants, but by explicitly deleting the move constructor you are also implicitly deleting the copy constructor. This leaves no non-copy elision option for the compiler, so it results in an error.