C++ – Why Destructors Disable Implicit Move Methods

c++c++11destructorlanguage-designmove-semantics

I was trying to understand what the rule of zero says by reading this blog. IMO, it says if you declare your own destructor then don't forget to make the move constructor and move assignment as default.

Example:

class Widget {
public:
  ~Widget();         // temporary destructor
  ...                // no copy or move functions
};

"The addition of the destructor has the side effect of disabling
generation of the move functions, but because Widget is copyable, all
the code that used to generate moves will now generate copies. In
other words, adding a destructor to the class has caused
presumably-efficient moves to be silently replaced with
presumably-less-efficient copies".

The above text by Scott Meyers, inside the quotes raise some questions in my mind:

  • Why declaring destructor hides the move semantics?
  • Is declaring/definig destructor only hides the move semantics or copy
    constructor and copy assignment as well hides the move semantics?

Best Answer

"The Rule of Zero" is in fact about something else than what special member functions are generated and when. It is about a certain attitude to class design. It encourages you to answer a question:

Does my class manage resources?

If so, each resource should be moved to its dedicated class, so that your classes only manage resources (and do nothing else) or only accumulate other classes and/or perform same logical tasks (but do not manage resources).

It is a special case of a more general Single Responsibility Principle.

When you apply it, you will immediately see that for resource-managing classes you will have to define manually move constructor, move assignment and destructor (rarely will you need the copy operations). And for the non-resource classes, you do not need to (and in fact you probably shouldn't) declare any of: move ctor/assignment, copy ctor/assignment, destructor.

Hence the "zero" in the name: when you separate classes to resource-managing and others, in the "others" you need to provide zero special member functions (they will be correctly auto-generated.

There are rules in C++ what definition (of a special member function) inhibits what other definitions, but they only distract you from understanding the core of the Rule of Zero.

For more information, see:

  1. https://akrzemi1.wordpress.com/2015/09/08/special-member-functions/
  2. https://akrzemi1.wordpress.com/2015/09/11/declaring-the-move-constructor/
Related Question