DoehJohn
DoehJohn

Reputation: 233

Why do we need default generated destructor

For what situations we need to have a default generated destructor? It's pretty clear why we would need default generated constructors and operator=, but can't think of situation when default generated destructor should be used.

class A
{
...
~A() = default;
...
};

Upvotes: 0

Views: 689

Answers (3)

Robert Andrzejuk
Robert Andrzejuk

Reputation: 5232

C++ Core Guidelines C.21: If you define or =delete any copy, move, or destructor function, define or =delete them all

Reason

The semantics of copy, move, and destruction are closely related, so if one needs to be declared, the odds are that others need consideration too.

Declaring any copy/move/destructor function, even as =default or =delete, will suppress the implicit declaration of a move constructor and move assignment operator. Declaring a move constructor or move assignment operator, even as =default or =delete, will cause an implicitly generated copy constructor or implicitly generated copy assignment operator to be defined as deleted. So as soon as any of these are declared, the others should all be declared to avoid unwanted effects like turning all potential moves into more expensive copies, or making a class move-only.

Note If you want a default implementation (while defining another), write =default to show you're doing so intentionally for that function. If you don't want a generated default function, suppress it with =delete.

So this mainly depends on what is declared in the class.

Generally it is about The rule of three/five/zero

If the class needs a custom copy/move function, but nothing special for a destructor, then =default should be used on the destructor.

Upvotes: 0

Ted Lyngmo
Ted Lyngmo

Reputation: 118097

In cases where you'd like to hide the implementation of a class inside an inner class and keep a unique_ptr to an instance of that inner class (the pimpl idiom) you need to move the default destructor definition out of the class definition since unique_ptr can't work with incomplete types.

Example:

A.hpp (the header a user of the class will include)

#pragma once
#include <memory>

class A {
public:
    A();
    ~A();
    void foo() const;
private:
    struct A_impl; // just forward declared
    std::unique_ptr<A_impl> pimpl;
};

A_impl.hpp ("hidden" - not to be included in normal usage of A)

#pragma once
#include "A.hpp"

struct A::A_impl {
    void foo() const;
};

A.cpp

#include "A_impl.hpp"

A::A() : pimpl(std::make_unique<A_impl>()) {}
A::~A() = default;                            // <- moved to after A_impl is fully defined
void A::foo() const { pimpl->foo(); }

A_impl.cpp

#include "A_impl.hpp"

#include <iostream>

void A::A_impl::foo() const { std::cout << "foo\n"; }

Demo

If you let the compiler generate A::~A() it will not compile. My compiler says:

unique_ptr.h:79:16: error: invalid application of ‘sizeof’ to incomplete type ‘A::A_impl’
     static_assert(sizeof(_Tp)>0,
                   ^~~~~~~~~~~

Demo

Upvotes: 2

Jeff Garrett
Jeff Garrett

Reputation: 7528

This seems to be asking when you would define the destructor for a class if the body of that destructor would be the same as the one the compiler generates.

Reasons include:

  1. Clarity. If you have a class with copy/move constructors or copy/move assignment operators, it is typically managing some resource. Many coding guidelines would require you define the destructor to show that it wasn't just overlooked, even it is equivalent to the compiler-generated one.
  2. Some aspect of the function differs from the one the compiler would generate. If you want a virtual destructor, you have to define it. Similarly, a throwing destructor must be defined.
  3. You want to control the place the destructor is generated. You can define a destructor outside of the class definition. You might need to do this for cyclically dependent classes as in one of the other answers. You may want to do this to define a stable ABI. You may want to do this to control code generation.

In all these cases, you must or want to define the destructor, even though the body is nothing special. Why would you use = default versus an empty body? Because the compiler-generated destructor is equivalent to the one you get with = default, and you only want to change the aspects of the destructor you are trying to change. An empty body is not the same as = default in C++, because a defaulted function can be defined as deleted. An empty body also rules out trivial destructibility, even if that was otherwise an option.

Upvotes: 0

Related Questions