GeneralPurpose-RuleOfThree

Certain special functions must always be declared together (e.g. copy constructor and copy assignment operator)

Required inputs: IR

If only some of the special member functions are explicitly declared, the compiler will generate the remaining special member functions. The compiler-generated implementations of these functions likely are inconsistent with the explicitly declared functions, which leads to resource management bugs such as dangling references and double frees.

In most cases, you should follow the Rule of Zero: resource management should be encapsulated in classes that do nothing except managing a single resource. Often, the classes std::unique_ptr or std::shared_ptr can be used for this purpose (with custom deleters). This frees up all other classes from the task of resource management: those classes should not define any special member functions, and rely on the compiler-generated default implementations instead.

When implementing a class that manages resources, follow the Rule of Three or Rule of Five:

  • Explicitly declare the copy constructor, copy assignment operator and destructor (copyable class without move semantics); or
  • Explicitly declare the move constructor, move assignment operator and destructor (non-copyable class with move semantics); or
  • Explicitly declare the copy constructor, copy assignment operator, move constructor, move assignment operator and destructor (copyable class with move semantics)
A class that is neither copyable nor movable still needs to follow these rules, but should mark the copy constructor and copy assignment operator as deleted.
Exception
A destructor with an empty body (or one defined as '= default;') does not require declaring any other special member functions. Empty destructors are functionally identical to the default destructor (which calls all member destructors), but may need to be defined explicitly if a member destructor can only be called in certain compilation units (e.g. std::unique_ptr<Incomplete_Type>).
References

Possible Messages

Key

Text

Severity

Disabled

missing_constructor_and_asgn

Class with destructor should also declare a copy or move constructor and assignment operator.

None

False

missing_copy_asgn

Class with copy constructor is missing copy assignment operator.

None

False

missing_copy_constructor

Class with copy assignment operator is missing copy constructor.

None

False

missing_destructor

Class with copy or move constructors or assignment operators should also declare a destructor.

None

False

missing_move_asgn

Class with move constructor is missing move assignment operator.

None

False

missing_move_constructor

Class with move assignment operator is missing move constructor.

None

False

Options

allow_defaulted_destructor_only

allow_defaulted_destructor_only : bool = True

Allow classes with a defaulted destructor and no other special member functions.
 

allow_destructor_only

allow_destructor_only : bool = False

Allow all destructors without copy or move constructors
 

allow_empty_destructor

allow_empty_destructor : bool = True

Allow empty destructors without copy or move constructors.
 

allow_missing_destructor

allow_missing_destructor : bool = False

Suppress messages about missing destructors.
 

allow_protected_destructor_only

allow_protected_destructor_only : bool = False

Allow a protected destructor without copy or move constructors
 

ignore_classes_ending_with_string

ignore_classes_ending_with_string : set[str] = set()

Do not report a class name that ends with one of the given strings.
 

ignore_classes_inheriting_from

ignore_classes_inheriting_from : set[bauhaus.analysis.config.QualifiedName] = set()

Do not report a class that inherits from one of the given classes.
 

ignore_classes_with_member_type

ignore_classes_with_member_type : set[bauhaus.analysis.config.QualifiedName] = set()

Do not report a class that has a member with one of the given types.
 

ignore_macro_expanded_classes

ignore_macro_expanded_classes : set[bauhaus.analysis.config.MacroName] = set()

Do not report a class expanded via one of the given macro names.
 

ignore_pod_classes

ignore_pod_classes : bool = True

Whether POD classes should be checked at all.