Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 968
Anubis Avatar asked Dec 17 '22 15:12

Anubis


2 Answers

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.

like image 197
eerorika Avatar answered Jan 04 '23 16:01

eerorika


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.

like image 41
Paul Evans Avatar answered Jan 04 '23 17:01

Paul Evans