3

I can understand defaulted constructors, since user defined constructors will disable the compiler generated ones making the object non trivially copyable etc.

In the destructor case, apart from changing access category, what use is there to define a defaulted destructor considering that no user defined member function can disable them (you can't overload destructors anyway) ?

// Which version should I choose ? 
struct Example 
{
    //1. ~Example() = default; 
    //2. ~Example() {}
    //3. 
}; 

Even in the case of virtual destructors, defaulting them would not make them trivial so what good is it doing it?

Nikos Athanasiou
  • 29,616
  • 15
  • 87
  • 153

4 Answers4

3

The exception for trivial destructors omission has to do with the derived class' destructor, not the base one. So virtual ~Foo() = default; is a useful construct to keep the default destructor, but virtualize it.

Quentin
  • 62,093
  • 7
  • 131
  • 191
  • 2
    Yes, but how does that differ from `virtual ~Foo() {}`. They both can't be trivial since they're virtual so what's to gain here? – Nikos Athanasiou Jul 28 '15 at 09:28
  • @NikosAthanasiou good point. I'd guess consistency, and clarity of intent. – Quentin Jul 28 '15 at 09:29
  • @NikosAthanasiou Uniformity? Just like `Foo() {}` is the same as `Foo() = default` w.r.t constructors. – legends2k Jul 28 '15 at 09:30
  • 3
    @legends2k `Foo() {}` is user provided thus non trivial so it differs from `Foo() = default` which is equivalent to having an implicitly defined one (a trivial one). Objects with trivial default constructors can be created by using `reinterpret_cast` on any suitably aligned storage, e.g. on memory allocated with `std::malloc`. All data types compatible with the C language (POD types) are trivially default-constructible. – Nikos Athanasiou Jul 28 '15 at 09:36
  • This should be an answer, not a comment – Jean-Bernard Jansen Jul 28 '15 at 09:54
  • 1
    @NikosAthanasiou Aah, my bad! In this case the standard says _user-provided_ as opposed to _user-declared_ like it does on (**[class.copy]**) the implicit move constructor ([see here](http://stackoverflow.com/a/17221752/183120)). I overlooked this difference. – legends2k Jul 28 '15 at 11:39
1

Basically it is about communicating the intent, but pretty redundant.

But in case you're using std::unique_ptr as a member of class you'll need to declare destructor (but only declare) in header. Then you can make it use default implementation in source file like so:

MyClass:~MyClass() = default;

Considering your options I would use first or third one.

Dino
  • 599
  • 1
  • 9
  • 20
1

As mentioned by Nikos Athanasiou in a comment, a default constructor makes the type trivially destructible, where a user defined one does not. A little code sample will show it:

#include <iostream>
#include <type_traits>

struct A { ~A() = default; };
struct B { ~B() {} };
struct C { ~C() noexcept {} };

int main() {
  std::cout
    << std::is_trivially_destructible<A>::value
    << std::is_trivially_destructible<B>::value
    << std::is_trivially_destructible<C>::value
    << std::endl;
  return 0;
}

Displays

100

As for virtual destructors, consistency with non-virtual ones and Quentin's answer are appropriate reasons. My personal advice is that you should always use the default when you can, as this is a way to stick to the most canonic behavior.

Community
  • 1
  • 1
Jean-Bernard Jansen
  • 7,544
  • 2
  • 20
  • 17
  • My comment was on default constructors and trivially constructible. I upvoted because the answer helps achieving completeness, but my question asserts that there's no case where ommiting a destructor is different than defaulting it since there's no case where user defined a member function can disable the implicit destructor. Apart from that a virtual destructor is never trivial (no matter if you default it) – Nikos Athanasiou Jul 28 '15 at 10:30
1

One use is making the destructor protected or private while potentially keeping the class trivial: just list it after the desired access specifier.

Another: when writing classes, some programmers like to order the class's functions: e.g. constructors, then the destructor, then the non-const "mutating" members, then the const "accessor" members, then static functions. By being able to explicitly = default the destructor, you can list it in the expected order and the reader looking there knows there can't be another misplaced version of it. In large classes, that may have some documentary/safety value.

It also gives you something concrete around which to add comments, which can help some documentation tools realise the comments relate to destruction.

Tony Delroy
  • 102,968
  • 15
  • 177
  • 252