0

I have some simple questions regarding C++ move constructor, but so far didn't find a post that explains specifically what I saw below...

#include <utility>

class A
{
public:
    A() {}
    A(const A &) { std::cout << "copy Ctor" << std::endl; }
    A(A&&) { std::cout << "move Ctor" << std::endl; }
};

int main()
{
    A a;
    A b(std::move(a));
}

The output is

move Ctor

If I explicitly delete the move constructor,

    // A(A&&) { std::cout << "move Ctor" << std::endl; }
    A(A&&) = delete;

I got compilation error,

error: use of deleted function ‘A::A(const A&&)’

so far so good.

Then I read that move constructor is not auto-generated when there is user-defined copy ctors, and I thought instead of explicit deletion, 'not declare it' should give the same result,

    // A(A&&) { std::cout << "move Ctor" << std::endl; }
    // A(A&&) = delete;

but then I got this output,

copy Ctor

Now I am confused,

  1. When I omit the declaration of move ctor, does A b(std::move(a)) calls copy ctor directly? Is that part of the C++ standard? For regular functions this seems true - when a function's parameter is a xvalue, the function taking rvalue reference is preferred, and fallback is the function taking const lvalue reference.
  2. But, if 'move constructor is not auto-generated when there is user-defined copy ctors', why 'explicit deletion' vs 'not declaring' makes a difference?
QnA
  • 1,035
  • 10
  • 25
  • Link I was considering as a duplicate until I decided it's more a related topic: [What is copy/move constructor choosing rule in C++? When does move-to-copy fallback happen?](https://stackoverflow.com/questions/24693950/what-is-copy-move-constructor-choosing-rule-in-c-when-does-move-to-copy-fallb) – user4581301 May 20 '21 at 00:19
  • There is probably a duplicate somewhere.... In the meantime, keep in mind that you are seeing an unusual result (explicit deletion making a difference) because you created an unusual situation (explicitly saying that copying is OK, and at the same time explicitly saying that moving is not). – JaMiT May 20 '21 at 00:21
  • See this answer https://stackoverflow.com/a/24694027/6752050 – 273K May 20 '21 at 00:22
  • 3
    One important thing to note is when you `delete` a method, the method "exists" and will take part in overload resolution, but it **cannot be used**. This makes for an excellent compile-time "warning" that things will not happen exactly as you might have wanted and the result is probably bad enough that you should stop and rethink. In fact you have to stop and rethink. [Good discussion](https://stackoverflow.com/questions/14085620/why-do-c11-deleted-functions-participate-in-overload-resolution) – user4581301 May 20 '21 at 00:25
  • 2
    Note also that adding `const` to your move constructor (`const A&&`) makes it basically useless. You want a non-const movable reference. – Raymond Chen May 20 '21 at 00:36
  • @RaymondChen you are right. – QnA May 20 '21 at 02:10
  • @user4581301 great answer and link, which answers my confusion about the delete usage perfectly. – QnA May 20 '21 at 02:11

1 Answers1

1

To make it somewhat easier to understand, I will use a somewhat unrelated example where the intended behavior might be a bit clearer.

Not much different that deleting a regular function:

struct A
{
    void f(int i) {}
    void f(double d) = delete;
};

A a;
a.f(1.1); // Error

If we comment out the second overload instead, then the first one will be used.

And it is quite obvious that it is an intended behavior as the purpose of deleting a function is to ensure that it is not called (if it is a better match than another overload).

Thus in my example above, one can easily prevent some undesirable conversions to happen.

Thyis is not much different than making a function private when public access is required. Deleting a function have the added benefit that it cannot be used from inside class member function. The other benefit is that the error happen at compile time instead of link time.

Phil1970
  • 2,605
  • 2
  • 14
  • 15