When an empty destructor is required
In last month's post Why you shouldn't provide an empty destructor, I taught you the difference between user-provided and user-declared. I hope you remember the conclusion; never provide an empty destructor. Either leave everything to the compiler or default the destructor (assuming there is no actual work for the destructor).
Hiding implementation details
So far, so good. I hope you followed this rule. As you probably know from life, not only programming. There is no rule without an exception. Let's talk about the one case that requires an empty destructor (yes, I know it sounds silly). Suppose you have the following code:
1 2 3 4 5 6 7 |
|
In A, you have a header file. The class Orange
should not be exposed at this point. Apple
only uses a pointer of type Orange
. A classic PImpl idiom or opaque pointer.
Later then, you use Apple
in B. Without the std::unique_ptr
, your code would compile. But with the std::unique_ptr
, you get the following error message(s):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
Essentially, this message tells you that the std::unique_ptr
cannot instantiate the required destructor for itself typed with Orange
. The simple reason is that, at this point, Orange
has no visible destructor. Which is the entire point of the PImpl idiom. What now?
Deviate from the rule (with a good reason)
It's time to violate our rule from last month. Time to provide an empty destructor for Apple
.
To delay the instantiation of the unique_ptr
s destructor, you must declare a destructor in Apple
. That way, the destructor of the unique_ptr
for mOrange
gets delayed.
1 2 3 4 5 6 7 |
|
Next, in the implementation file for Apple
, you provide the definition for the destructor.
1 |
|
I personally would prefer =default
like this:
1 |
|
But this time, the variant you use makes no difference for code generation because you look at an out-of-line definition. I would use =default
for consistency reasons to avoid the empty curly braces.
Andreas