Move semantics and copy constructor

2019-08-16 14:28发布

问题:

I wrote a program as below:

#include <iostream>

using namespace std;

class A {
public:
    A() {
    }
    A(A &a) {
        id = a.id;
        cout << "copy constructor" << endl;
    }
    A& operator=(A &other) {
        id = other.id;
        cout << "copy assignment" << endl;
        return *this;
    }
    A(A &&other) {
        id = other.id;
        cout << "move constructor" << endl;
    }
    A& operator=(A &&other) {
        id = other.id;
        cout << "move assignment" << endl;
        return *this;
    }
public:
    int id = 10;
};

A foo() {
    A a;
    return a;
}

int main()
{
    A a;
    A a2(a); // output: copy constructor
    A a3 = a2; // output: copy constructor
    a3 = a2; // output: copy assignment
    A a4 = foo(); // output: 
    a4 = foo(); // output: move assignment
    return 0;
}

I compiled it on my Mac OS. The output is:

copy constructor
copy constructor
copy assignment
move assignment

My question are:

  1. Why the output of A a4 = foo(); is empty? I thought it should call the move constructor.
  2. Why the output of A a3 = a2; is copy constructor instead of copy assignment?

回答1:

  1. Because copies and moves may be elided by the compiler if it wishes. The relevant constructor must still exist, but it is explicitly stated in the standard that they might not be invoked. (This is a rare example of a standard-defined optimisation, in particular allowing Return Value Optimisation to be standard-defined also.)

  2. Because the use of = in initialisation performs construction, not assignment. It's somewhat confusing that this is the syntax. A a3(a2), which is [essentially] equivalent, would be clearer in this regard.



回答2:

The compiler is generating default methods for:

A (const A &);
A & operator = (const A &);

If you add the const qualifier to your copy ctor / assign methods, you may see the results you expect.