C++ Logo

std-discussion

Advanced search

Is an implementation required to define an unneeded, implicitly declared as defaulted, virtual destructor?

From: Mark Stegeman <mpstegeman_at_[hidden]>
Date: Sat, 2 Nov 2019 15:15:41 +0100
Hi list,

I'm having some trouble determining the validity of the following C++17
code:

----
#include <memory>
struct Base {
    virtual ~Base() = default;
};
struct Bar;
struct Foo : Base {
    std::unique_ptr<Bar> bar_{};
};
----
The following standard quotes lead me to believe that this is ill-formed:
[class.dtor]/4
If a class has no user-declared destructor, a destructor is implicitly
declared as defaulted. [...]
[class.dtor]/10
[...] If a class has a base class with a virtual destructor, its destructor
(whether user- or implicitly-declared) is virtual.
[class.dtor]/7
A destructor that is defaulted and not defined as deleted is implicitly
defined when it is odr-used or when it is explicitly defaulted after its
first declaration.
[class.dtor]/5
A defaulted destructor for a class X is defined as deleted if:
 - X is a union-like class that has a variant member with a non-trivial
destructor,
 - any potentially constructed subobject has class type M (or array
thereof) and M has a deleted destructor or a destructor that is
inaccessible from the defaulted destructor,
 - or, for a virtual destructor, lookup of the non-array deallocation
function results in an ambiguity or in a function that is deleted or
inaccessible from the defaulted destructor.
[basic.def.odr]/3
[...] A virtual member function is odr-used if it is not pure. [...]
I would interpret these quotes as: ~Foo() must be implicitly defined,
because it is virtual, defaulted, and not defined as deleted. This ~Foo()
must invoke ~std::unique_ptr<Bar>(), which invokes
std::default_delete<Bar>, which makes the program ill-formed, because Bar
is incomplete.
However, practically speaking, since no Foo's are created, there should be
no reason to define ~Foo() here. The description of CWG2068 indeed suggests
that the intended interpretation is that implementations are not required
to define ~Foo() in this example. And the implementations I checked (MSVC,
gcc, clang) all accept it as well. So it looks like my interpretation is
wrong, but I haven't been able to find why.
Could you tell me where my interpretation goes wrong? What have I missed?
Thanks
See https://stackoverflow.com/q/58543232 for a previous discussion

Received on 2019-11-02 09:18:11