The Zero Confusion Rule?

So I read about Rule of Zero .

Simplified version: I don't understand the purpose of this rule. The rule of three and five is kind of a "rule of thumb", but I can't see the "rule of thumb" or any other specific intent with this rule.

Detailed version:

Let me quote:

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

What does it mean? What do they mean by owning, owning what? They also showed some sample code (I think it's linked to the introduction):

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

      

What they want to show with this, I really lost it.

In addition, they also talk about the scenario when you are dealing with a polymorphic class and the destructor is declared public and virtual, and the fact that this block is implicitly moved. Therefore, you must declare them all as default:

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 declared both public and virtual, you really need to declare all other special member functions as default? If so, I don't understand why.

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

+3


source to share


1 answer


Zero rule

The zero rule is another correct rule about how to write classes that should use some resources like memory or other objects. In this example, the dynamically allocated memory containing the characters in the string is a resource that must be managed.

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

This rule came about after the introduction of C ++ 11, as the language and standard library improved to provide much better options for managing dynamically allocated object lifetimes (unique_ptr and shared_ptr). Additionally, containers can now be built in place, eliminating another reason for dynamic allocation. This should probably be seen as an update to the older rule of three.

So, if you previously used new in your constructor to create a member and delete in a destructor, you should now use unique_ptr to manage the member lifetime, get the move construct, and "free" redirects.

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



Thus, basically a class that can rely on its members to perform all the necessary actions to initialize, move, copy, and destroy does not have to declare any of the special member functions.

Rule of five

As always with C ++ things aren't always that simple.

As Scott Meyers pointed out, if you need to add a destructor for any reason, the implicit generation of move constructors and the move assignment operator are disabled, even though the compiler can generate them.

The compiler will then happily copy your class all over the place rather than moving it around, which may not be what you expect. This can slow down your program as more copying is required. The compiler will not warn about this by default.

Therefore, he recommends that you clearly state which of the five custom methods you want to avoid surprises from unrelated changes. He still recommends writing non-resource classes so that compiler-generated defaults can be used.

+2


source







All Articles