38
votes

I want to prevent the user of my class from using it as an automatic variable, so I write code like this:

class A {
private:
  ~A() = default;
};

int main() {
  A a;
}

I expect that the code won't be compiled, but g++ compiles it without error.

However, when I change the code to:

class A {
private:
  ~A(){}
};

int main() {
  A a;
}

Now, g++ gives the error that ~A() is private, as is my expectation.

What's the difference between a "= default" destructor and an empty destructor?

1
What version of gcc? - user3920237
Reading e.g. this destructor reference, the difference is that a user-provided destructor (even if it's empty) is non-trivial, and from the reference: "Objects with trivial destructors don't require a delete-expression and may be disposed of by simply deallocating their storage." - Some programmer dude
In your case there is no difference, both gcc4.9 and clang3.5 refuse to compile your first example. It must be a bug in your version of gcc. - Praetorian
The version of my gcc is 4.8.2 - delphifirst
I think the relevant bug report is 54812 - user3920237

1 Answers

28
votes

Your first example should not compile. This represents a bug in the compiler that it does compile. This bug is fixed in gcc 4.9 and later.

The destructor defined with = default is trivial in this case. This can be detected with std::is_trivially_destructible<A>::value.

Update

C++11 (and C++14) state that if one has a user-declared destructor (and if you don't have either user-declared move special member), then the implicit generation of the copy constructor and copy assignment operator still happen, but that behavior is deprecated. Meaning if you rely on it, your compiler might give you a deprecation warning (or might not).

Both:

~A() = default;

and:

~A() {};

are user-declared, and so they have no difference with respect to this point. If you use either of these forms (and don't declare move members), you should explicitly default, explicitly delete, or explicitly provide your copy members in order to avoid relying on deprecated behavior.

If you do declare move members (with or without declaring a destructor), then the copy members are implicitly deleted.