Why are the default move ctor and assignment no longer added by the compiler when defining the destructor?

I cannot understand the rationale for automatically adding default codes. In particular, I find it very inconvenient that every time I just need to add an empty virtual destructor and nothing more, I lose material to move, but adding them, I lose copies and things by default, so I end up adding this whole piece code

virtual ~SomeClass(){} // you are the guilty! //virtual ~SomeClass() = default // would be the same SomeClass(SomeClass&&) = default; // no more auto-added SomeClass& operator=(SomeClass&&) = default; // no more auto-added SomeClass(const SomeClass&) = default; // but with the moves defined, SomeClass& operator=(const SomeClass&) = default; // I'm now missing the copy SomeClass(){} // and the default as well 

I am sure that there is a reason to make my lessons ugly and allow me to wish for an evil macro, I just would like it to become more comfortable.

+6
source share
2 answers

Take a look. It explains what is called the rule of five, which essentially complies with the standard.

Typically, in most cases, the compiler creates default values ​​for the copy constructor, copy destination, transfer destination, and destructor. But, if the programmer defines any of them, then the compiler assumes that the user has encapsulated something in this class that requires his / her special, let's say. destructor. Now that the programmer knows that he needs a destructor, the compiler will know that the programmer knows what is happening and simply does not create default values ​​for the rest (because, based on the assumption that the compiler does, by default they will be erroneous and may even lead to unwanted behavior).

+1
source

The problem is that your class is trying to do two separate things: providing a polymorphic interface (hence the need for a virtual destructor) and managing specific data members (hence the need for copy / move operations). It is usually a good idea to give each class one responsibility.

I would move the virtual destructor and any virtual function declarations into an empty abstract base class. Then any particular class (s) resulting from this will be free to auto-generate all the necessary things.

Example:

 #include <iostream> struct Movable { Movable() {} Movable(Movable&&m) {std::cout << "Moving\n";} }; struct SomeInterface { virtual ~SomeInterface() {} // no data members, so no need for any other special member functions }; struct SomeClass : SomeInterface { Movable stuff; // no user-declared special functions, so all are auto-generated }; int main() { SomeClass c; SomeClass c2(std::move(c)); // uses the auto-generated move constructor } 
0
source

Source: https://habr.com/ru/post/972781/


All Articles