C++ and the Rule of Zero, Three, and Five
The Rule of Zero, Three, and Five
TL;DR
If you define the destructor, copy constructor, or move constructor, then all three should be defined.
If you don’t define any of those, and you also do not define the copy assignment operator nor the move assignment operator, then you don’t need to define any of the five.
However, the best practice is to always define all 5 of the rules (i.e. explicitly specify what you want for a copy/move constructor, copy/move assignment operator, and virtual destructor). If you just want the default, then you can explicitly declare them as defaults in the header. If you need to customize or prevent their action, then define or delete as necessary.
The Rule of Five (C++11 and beyond)
If you define a destructor, copy constructor, or copy assignment operator, then your class will not support move semantics, unless you explicitly add them.
If you wanted to just use the default destructor and constructors with copy and move semantics you can do this:
class Robot { public: Robot(); // Default Constructor // These are the five: Robot(const Robot&) = default; // Copy Constructor Robot(Robot&&) = default; // Move Constructor Robot& operator=(const Robot&) = default; // Copy Assignment Operator Robot& operator=(Robot&&) = default; // Move Assignment Operator virtual ~Robot() = default; // Destructor };
The Rule of Three (before C++11)
If you define a destructor, copy constructor, or copy assignment operator, then the compiler will add all three and they will probably be wrong (because what the compiler does will probably be different than what you did in the one[s] you defined).
The virtual destructor is very important for classes that will be extended. This is needed, because it is the only way that this parent class destructor will be called when a child object is destroyed, and the parent should cleanup after itself.
If you wanted to just use the default destructor and constructors with copy semantics, but remove move semantics then (notice ‘delete’):
class Robot { public: Robot(); // Default Constructor // These are the three: Robot(const Robot&) = default; // Copy Constructor Robot(Robot&&) = delete; // Delete Move Constructor Robot& operator=(const Robot&) = default; // Copy Assignment Operator Robot& operator=(Robot&&) = delete; // Delete Move Assignment Operator virtual ~Robot() = default; // Destructor };
The Rule of Zero
If you don’t have custom logic for a destructor, copy constructor, move constructor, copy assignment operator, or move assignment operator, then don’t define them.
The default constructors and destructors with copy semantics:
class Robot { public: Robot(); // Default Constructor // These are the five: Robot(const Robot&) = delete; // Delete Copy Constructor Robot(Robot&&) = delete; // Delete Move Constructor Robot& operator=(const Robot&) = delete; // Delete Copy Assignment Operator Robot& operator=(Robot&&) = delete; // Delete Move Assignment Operator virtual ~Robot() = default; // Destructor };
Keeping it Simple (C++11 and beyond)
As explained in the “Too Long; Didn’t Read” section at the top:
The best practice is to always define all 5 of the rules (i.e. explicitly specify what you want for a copy/move constructor, copy/move assignment operator, and virtual destructor). If you just want the default, then you can explicitly declare them as defaults in the header. If you need to customize or prevent their action, then define or delete as necessary.
This pretty much means to start with the defaults. If it doesn’t make sense to support copy or move then explicitly delete them. If you decide to implement a custom definition, then define or delete the others. Use logic when deciding what to do with the destructor.
Start with the defaults:
class Robot { public: Robot(); // Default Constructor // These are the five: Robot(const Robot&) = default; // Copy Constructor Robot(Robot&&) = default; // Move Constructor Robot& operator=(const Robot&) = default; // Copy Assignment Operator Robot& operator=(Robot&&) = default; // Move Assignment Operator virtual ~Robot() = default; // Destructor };
References
CPP References Site
WikiPedia
Clean Code book
Categories