Rule of Zero confusion?
Asked Answered
A

2

14

So I have been reading about the Rule of Zero.

Simplified version: I do not understand the purpose of this rule. The rule of three and five are sort of "rule of thumbs", but I cannot see the "rule of thumb" or any other specific intentions with this rule.

Detailed version:

Let me quote:

Classes that have custom destructors, copy/move constructors or copy/move assignment operators should deal exclusively with ownership. Other classes should not have custom destructors, copy/move constructors or copy/move assignment operators.

What does this mean? What do they mean by ownership, ownership of what? They have also showed an example code(I guess it is connected to the introduction):

class rule_of_zero
{
    std::string cppstring;
 public:
    rule_of_zero(const std::string& arg) : cppstring(arg) {}
};

What do they want to show with this, I am really lost on this one.

Also, they are also talking about the scenario when you are dealing with a polymorphic class and the destructor is being declared public and virtual and the fact that this block implicit moves. Therefore, you have to declare them all as defaulted:

class base_of_five_defaults
{
 public:
    base_of_five_defaults(const base_of_five_defaults&) = default;
    base_of_five_defaults(base_of_five_defaults&&) = default;
    base_of_five_defaults& operator=(const base_of_five_defaults&) = default;
    base_of_five_defaults& operator=(base_of_five_defaults&&) = default;
    virtual ~base_of_five_defaults() = default;
};

Does this mean that whenever you have a base class with a destructor that is declared both public and virtual, you really have to declare all the other special member function as defaulted? If so, I do not see why.

I know that this is a lot of confusion in one place.

Align answered 9/7, 2017 at 15:18 Comment(3)
Ownership == responsibility for the lifecycle of a managed resource. For example, the various smart pointer classes model different kinds of ownership (shared vs. unique, etc.)Kennard
By the way "rules of thumb" are rules that you should generally adhere to for best practice. There isn't actually a rule called the "Rule of thumb".Carolyncarolyne
@OliverCharlesworth, thanks. However, that was only a tiny part of my confusion :(Align
W
19

The Rule of Zero

The rule of zero is another rule of thumb about how to write classes that need to use some resources like memory or other objects. In the example the dynamically allocated memory containing the characters of the string is a resource that has to be managed.

The recommendation is to let specialized classes manage resources, and do only that. In the example, std::string takes care of all the details of managing the allocated memory.

The rule emerged after the introduction of C++11, because the language and the standard library had improved, providing much better facilities to manage dynamically allocated object lifetimes (unique_ptr and shared_ptr). Also the containers now allow in-place construction, removing another reason for dynamic allocation. It should probably be seen as an update to the much older rule of three.

So if you previously would have used new in your constructor to create some member and delete in the destructor, you should now use a unique_ptr to manage the lifetime of the member, getting move construction and move assignment "for free".

Shared pointers can remember the correct destructor to call, so the common need for a virtual destructor goes away for objects that are exclusively managed via shared pointer, even if they are used polymorphically.

So basically a class that can rely on its members to do all the required actions for initialization, moving, copying and destruction should not declare any of the special member functions.

The Rule of Five

As always with C++ things are not always that simple.

As Scott Meyers pointed out, if you do have to add a destructor for whatever reason, the implicit generation of move constructors and move assignment operator are disabled, even if the compiler could generate them.

Then the compiler will happily copy your class all over the place instead of moving it which may not be what you expect. This may for example slow down your program, as more copying has to be performed. The compiler will not warn about this by default.

Therefore he recommends to explicitly specify which of the five special methods you want, in order to avoid surprises due to unrelated changes. He still recommends writing non-resource-management classes such that the defaults generated by the compiler can be used.

Wellesley answered 10/7, 2017 at 15:41 Comment(0)
M
-2

According to SonarCloud :

Classes that avoid directly handling resources don’t need to define any of the special member functions required to properly handle resources: destructor, copy constructor, move constructor, copy assignment operator, and move assignment operator. That’s because the versions of those functions provided by the compiler do the right thing automatically, which is especially useful because writing these functions correctly is typically tricky and error-prone. Omitting all of these functions from a class is known as the Rule of Zero because no special function should be defined. This rule should apply to the vast majority of classes.

So according to SonarCloud, the Rule of Zero only consists in not declaring the destructor, the copy-constructor, the copy-assignment operator, the move constructor and the move assignment operator.

Mccarron answered 11/7 at 14:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.