15

I would like to disable the move constructor in the class. Instead of moving, I would like to base on copy constructor. When I try to write this code:

class Boo
{
public:
    Boo(){}
    Boo(const Boo& boo) {};
    Boo(Boo&& boo) = delete;
};

Boo TakeBoo()
{
    Boo b;
    return b;
}

during compilation I received error:

error C2280: 'Boo::Boo(Boo &&)': attempting to reference a deleted function

How can I disable the move constructor and force copies instead?

Niall
  • 30,036
  • 10
  • 99
  • 142
user5929018
  • 191
  • 1
  • 6
  • 6
    just don't overload the move constructor and the compiler won't generate a move constructor for it since there is already a copy constructor – David Haim Feb 15 '16 at 09:37
  • 2
    From the standard: "If the definition of a class X does not explicitly declare a move constructor, one will be implicitly declared as defaulted if and only if X does not have a user-declared copy constructor [...] When the move constructor is not implicitly declared or explicitly supplied, expressions that otherwise would have invoked the move constructor may instead invoke a copy constructor." – Pixelchemist Feb 15 '16 at 09:41
  • 1
    What do you hope to achieve by this? It doesn't appear to be meaningful in any way. – Cheers and hth. - Alf Feb 15 '16 at 10:17
  • I'm trying to develop some micro-kernel architecture implementation using dll as modules exposing services. And the challenge is how to expose API to avoid binary compatibility problems related to different CRT (e.g debug/release) in different modules. And possibility to customize how objects are returned between dll boundaries is very useful during implementation. – user5929018 Feb 15 '16 at 13:26

2 Answers2

26

Do not create any move constructor:

class Boo
{
public:
    Boo(){}
    Boo(const Boo& boo) {};
};

The move constructor is not automatically generated as long as a user-defined copy constructor is present so the copy constructor is called.

YSC
  • 38,212
  • 9
  • 96
  • 149
Marian Spanik
  • 1,079
  • 1
  • 12
  • 18
  • 7
    The move constructor is not automatically generated *if a copy constructor is present*. This is the case in the OP's example, but it's worth pointing out, lest a reader conclude that not implementing a move constructor is enough to avoid moves. For example, a class with two `std:: vector` members and no copy or move constructors implicitly defined will get an auto-generated move constructor that moves the vectors. – user4815162342 Feb 15 '16 at 09:44
10

Marking a function as =delete makes the function available for overload resolution, but if chosen, the compilation fails; this functionality is not limited to constructors and other special functions (see here). Previously (circa C++03) making the member private achieved a similar result.

Hence, the code as in the sample, effectively means you prohibiting the construction of an object of the class from a temporary or expiring value (rvalues) - the move constructor.

To correct this, remove the move constructor completely. In the case of the class, once a copy constructor is present (user defined), the move is implicitly not generated anyway (move constructor and move assignment operator).

class Boo
{
public:
    Boo(){}
    Boo(const Boo& boo) {};
    //Boo(Boo&& boo) = delete;
};
Community
  • 1
  • 1
Niall
  • 30,036
  • 10
  • 99
  • 142
  • 2
    Extra info: marking the move constructor as deleted yourself does indeed make it available for overload resolution; however if the move-constructor is implicitly defined as deleted (e.g. this happens if a member variable has its move constructor defined as deleted, either implicitly or explicitly) then it is *not* available for overload resolution!. (overload resolution is fun...) – M.M Feb 15 '16 at 13:11