Why does destructor disable generation of implicit move methods?

后端 未结 4 1021
情书的邮戳
情书的邮戳 2020-12-03 03:14

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 a

相关标签:
4条回答
  • 2020-12-03 03:37

    is declaring/defining Dtor only hide the move semantics or copy ctor/copy assignment as well hide the move semantics?

    If no user-defined move constructors are provided for a class all of the following is true:

    • 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

    then the compiler will declare a move constructor as a non-explicit inline public member of its class with the signature T::T(T&&).

    Thus, yes declaring a copy constructor or an assignment operator hides implicitly declared move constructor as well.

    0 讨论(0)
  • 2020-12-03 03:42

    First I would say Mats Petersson's answer is better than the accepted one as it mentions the rationale.

    Second, as a supplement, I want to elaborate a bit more.

    The behavior of implicitly-declared (or defaulted) move ctor

    From c++draft:

    The implicitly-defined copy/move constructor for a non-union class X performs a memberwise copy/move of its bases and members.

    The condition when compiler implicitly declares a move ctor

    From cppreference:

    If no user-defined move constructors are provided for a class all of the following is true:

    • 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

    then the compiler will declare a move constructor as a non-explicit inline public member of its class with the signature T::T(T&&).

    Why dtor(and many others) prevents implicitly-declared move ctor?

    If we look at the above conditions, not only user-declared destructor prevents implicitly-declared move ctor, user-declared copy constructor, user-declared copy assignment operator and user-declared move assignment operator all has the same prevention effect.

    The rationale, as Mats Petersson has pointed out, is that:

    If the compiler thinks you might need to do something other than memberwise move in move operation, then it is not safe to assume you don't need it.

    • When there are user-declared destructors, which means there's some clean up work to do, then you probably want to do it with the moved-from object.

    • When there are user-declared move assignment operators, since it's also "moving" resources, you probably want to do the same in move ctor.

    • When there are user-declared copy constructors or copy assignment operators, this is the most interesting case. We know that move semantics allows us to keep value semantics while gaining performance optimization, and that move will "fall back" to copy when move ctor is not provided. In some way, move can been seen as the "optimized copy". Therefore, if the copy operation requires us to do something, it is likely that similar work is also needed in move operation.

    Since in the above conditions, something other than memberwise move might needs to be done, the compiler will not assume you don't need it, and thus won't implicitly declare a move ctor.

    0 讨论(0)
  • 2020-12-03 03:45

    "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/
    0 讨论(0)
  • 2020-12-03 04:04

    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.

    0 讨论(0)
提交回复
热议问题