Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does destructor disable generation of implicit move methods?

Tags:

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?
like image 271
RaGa__M Avatar asked Nov 26 '15 07:11

RaGa__M


People also ask

Why destructor prevents implicit move constructor?

there are no user-declared copy constructors. there are no user-declared copy assignment operators. there are no user-declared move assignment operators. there are no user-declared destructors.

Is destructor called after move?

uninitialized_move() initializes new T objects into the new memory area by moving them from the old memory area. Then it calls the destructor on the original T object, the moved-from object.

What does implicit move constructor do?

Implicitly-defined move constructor For non-union class types (class and struct), the move constructor performs full member-wise move of the object's bases and non-static members, in their initialization order, using direct initialization with an xvalue argument.

What is destructor and its type?

A destructor takes no arguments and has no return type. Its address cannot be taken. Destructors cannot be declared const , volatile , const volatile or static . A destructor can be declared virtual or pure virtual .


2 Answers

"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/
like image 115
Andrzej Avatar answered Sep 24 '22 00:09

Andrzej


Almost always, if you have a destructor (that "does something"), you should follow the "rule of three", which then becomes "rule of five" if you want move semantics.

If your destructor is empty, then it's not needed. So the implication is that a non-empty destructor (because you wouldn't have one if it's not needed!), then you also need to do the same thing in copy and assignment operations, and presumably, move construction and move assignment will need to "do something", and not just transfer the actual content across.

Of course, there may be cases where this is not true, but the compiler takes the approach of "let's only apply the automatically generated move functions if the destructor is empty", because that is the "safe" approach.

like image 38
Mats Petersson Avatar answered Sep 23 '22 00:09

Mats Petersson