Anubis
Anubis

Reputation: 7425

How to properly implement a C++ class destructor

In a class (without direct pointer members), I see there are following 3 possibilities for defining a destructor.

class Child : public Parent
{
public:
    // ~Child() override {}          // (1) explicit destructor with empty body
    // ~Child() override = default;  // (2) explicit default destructor
    //                               // (3) implicit default destructor


private:
    // members
}

Can/should option (1) always be avoided? Because Clang-Tidy hints me to take option (2) if I use option (1).

What are the differences between the three different options in general? What should be considered when selecting one over others?

Upvotes: 4

Views: 2129

Answers (3)

eerorika
eerorika

Reputation: 238311

Can/should option (1) always be avoided?

Assuming non-ancient version of the language, yes. As far as I can tell, only reason to use an empty non-default destructor is to support C++03 and older standard.

What should be considered when selecting one over others?

    1. and 3. Have the advantage of being valid in all versions of C++ (disregrading the override specifier).
    1. and 3. Have the advantage of being trivial as long as members are trivially destructable.
    1. and 2. have the advantage of allowing the destructor to be defined separately from the class definition (which was not taken advantage of in the example). This is crucial for example if you have a unique pointer to incomplete type as a member. This is typical when implementing the PIMPL pattern.
    1. and 2. also have the advantage of allowing the destructor be explicitly declared virtual, which is usually necessary for polymorphic base classes.
    1. Has the disadvantage of making the use of implicitly declared copy constructor and assignment operator deprecated. This means it should not be relied on, and may potentially stop working in future. Both 1. and 2. have the disadvantage of preventing implicit move constructor and assignment operator generation. So, if you use either, then you should also declare the copy and move constructors and assignment operators (as defaulted if possible).
    1. Has the advantage of being least amount to write and least amount to read, especially considering the previous paragraph.

As a rough rule of thumb, use 3. if possible. If not possible (for example, the PIMPL case described above), then use 2. If not possible (i.e. you need to support C++03), then use 1.

Upvotes: 5

bolov
bolov

Reputation: 75688

C++ uses RAII principle. Closely related there is The rule of three/five/zero.

It goes like this:

  • if your class is the owner of a resource, then it must implement all 3/5 special members (copy/move constructor, copy/move assignment and destructor) in order to respect the RAII principle
  • in accordance if you need to define at least one of the 3/5 special members then your class is most likely owning a resource so you must define all 3/5
  • if your class is owning a resource then it must deal exclusively with the booking of that resource. Else it should not define any of the special members mentioned (Rule of zero).

You are definitely in the Rule of Zero territory as should be all of your code. So you need to have the implicit destructor.

Upvotes: 3

Paul Evans
Paul Evans

Reputation: 27567

Can/should option (1) always be avoided?

If you have nothing to put into a destructor, then you should let the compiler generate a default destructor for you, so Yes.

What are the differences between the three different options in general?

Assuming that there's nothing special that needs to be put in your destructor:

  1. You lock the destrucor into being empty, if things change you might forget to add them into your destructor.

  2. Let the compiler figure it all out and show in the code that your doing this.

  3. Let the compiler figure it all out and don't show in the code that your doing this.

Upvotes: 3

Related Questions