What is copy/move constructor choosing rule in C++? When does move-to-copy fallback happen?

c++, c++11, copy-constructor, move-constructor

Solution

There is no "fallback". It is called overload resolution. If there are more than one possible candidate in overload resolution then the best match is chosen, according to a complicated set of rules which you can find by reading the C++ standard or a draft of it.

Here is an example without constructors.

class X { };

void func(X &&) { cout << "move\n"; }            // 1
void func(X const &)  { cout << "copy\n"; }      // 2

int main()
{
    func( X{} );
}

- As-is: prints "move"

- Comment out "1": prints "copy"

- Comment out "2": prints "move"

- Comment out "1" and "2": fails to compile

In overload resolution, binding rvalue to rvalue has higher preference than lvalue to rvalue.

Here is a very similar example:

void func(int) { cout << "int\n"; }      // 1
void func(long) { cout << "long\n"; }    // 2

int main()
{
     func(1);
}

- As-is: prints "int"

- Comment out "1": prints "long"

- Comment out "2": prints "int"

- Comment out "1" and "2": fails to compile

In overload resolution, an exact match is preferred to a conversion.

In your three examples on this thread we have:

1: Two candidate functions; rvalue prefers rvalue (as in my first example)

A(const A&);
A(A&&);           // chosen

2: Two candidate functions; rvalue prefers rvalue (as in my first example)

A(const A&); 
A(A&&);           // chosen

3: One candidate function; no contest

A(const A&);      // implicitly declared, chosen

As explained earlier, there is no implicit declaration of A(A&&) in case 3 because you have a destructor.

For overload resolution it does not matter whether the function body exists or not, it is whether the function is declared (either explicitly or implicitly).

Problem

The first example: ``` #include <iostream> #include <memory> using namespace std; struct A { unique_ptr<int> ref; A(const A&) = delete; A(A&&) = default; A(const int i) : ref(new int(i)) { } ~A() = default; }; int main() { A a[2] = { 0, 1 }; return 0; } ``` It works perfectly. So here the MOVE constructor is used. Let's remove the move constructor and add a copy one: ``` #include <iostream> #include <memory> using namespace std; struct A { unique_ptr<int> ref; A(const A&a) : ref( a.ref.get() ? new int(*a.ref) : nullptr ) { } A(A&&) = delete; A(const int i) : ref(new int(i)) { } ~A() = default; }; int main() { A a[2] = { 0, 1 }; return 0; } ``` Now the compilation falls with the error "use of deleted function ‘A::A(A&&)’" So the MOVE constructor is REQUIRED and there is no fall back to a COPY constructor. Now let's remove both copy- and move-constructors: ``` #include <iostream> #include <memory> using namespace std; struct A { unique_ptr<int> ref; A(const int i) : ref(new int(i)) { } ~A() = default; }; int main() { A a[2] = { 0, 1 }; return 0; } ``` And it falls with "use of deleted function ‘A::A(const A&)’" compilation error. Now it REQUIRES a COPY constructor! So there was a fallback (?) from the move constructor to the copy constructor. Why? Does anyone have any idea how does it conform to the C++ standard and what actually is the rule of choosing among copy/move constructors?

Original source