The rule of zero is a C++ design guideline: declare none of a class’s six special member functions and let the compiler provide their defaults. The six are the default constructor, copy constructor, copy assignment, move constructor, move assignment, and destructor. Less handwritten code can mean fewer bugs, especially when the class does not manage memory or resource handles. section 6.1.1 section 6.3
Apply the guideline with these practical qualifications:
- Keep the defaults when a class owns no resources requiring custom cleanup. section 6.1.1
- Treat polymorphic base classes differently: a base used through pointers needs a virtual destructor, even though declaring it means the class is no longer a strict rule-of-zero example. section 6.1.1 section 6.3
- Remember that declaring a destructor or another special member can block implicitly generated move operations; explicitly declare or delete the needed members when moving or copying matters. section 6.1.4
- Use type traits such as std::is_move_constructible_v and std::is_copy_assignable_v to check the resulting type properties. section 6.1.4
A polymorphic Blob base class
A first Blob base class declares only pure virtual step and total_steps functions, so its six special members are defaulted. Because a derived Blob may be deleted through a base pointer, the refined version adds virtual ~Blob() = default and explicitly deletes copying. This illustrates the boundary between accepting defaults and making deliberate special-member choices. section 6.1.1 section 6.1.4
Listing 6.2 A better base class
#pragma once
namespace Race
{
class Blob
{
public:
virtual ~Blob() = default; #1
Blob() = default; #2
Blob(Blob const&) = delete; #3
Blob& operator=(Blob const&) = delete; #3
virtual void step() = 0;
virtual int total_steps() const = 0;
};
}
Inspect the refined Blob declaration showing a defaulted virtual destructor and deleted copy operations. section 6.1.1
