The following code compiles and links with Visual Studio
(both 2017 and 2019 with /permissive-
), but does not compile with either gcc
or clang
.
foo.h
#include <memory> struct Base { virtual ~Base() = default; // (1) }; struct Foo : public Base { Foo(); // (2) struct Bar; std::unique_ptr<Bar> bar_; };
foo.cpp
#include "foo.h" struct Foo::Bar {}; // (3) Foo::Foo() = default;
main.cpp
#include "foo.h" int main() { auto foo = std::make_unique<Foo>(); }
My understanding is that, in main.cpp
, Foo::Bar
must be a complete type, because its deletion is attempted in ~Foo()
, which is implicitly declared and therefore implicitly defined in every translation unit that accesses it.
However, Visual Studio
does not agree, and accepts this code. Additionally, I've found that the following changes make Visual Studio
reject the code:
(1)
non-virtual(2)
inline -- i.e. Foo() = default;
or Foo(){};
(3)
It looks to me as if Visual Studio
does not define an implicit destructor everywhere it is used under the following conditions:
Instead, it seems to only define the destructor in the translation unit that also contains the definition for the constructor in the second condition.
So now I'm wondering:
Visual Studio
does this?Update: I've filed a bug report https://developercommunity.visualstudio.com/content/problem/790224/implictly-declared-virtual-destructor-does-not-app.html. Let's see what the experts make of this.
I believe this is a bug in MSVC. As for the std::default_delete::operator()
, the Standard says that [unique.ptr.dltr.dflt/4]:
Remarks: If T is an incomplete type, the program is ill-formed.
Since there is no "no diagnostic required" clause, a conforming C++ compiler is required to issue a diagnostic [intro.compliance/2.2]:
If a program contains a violation of any diagnosable rule or ..., a conforming implementation shall issue at least one diagnostic message.
together with [intro/compliance/1]:
The set of diagnosable rules consists of all syntactic and semantic rules in this document except for those rules containing an explicit notation that “no diagnostic is required” or which are described as resulting in “undefined behavior”.
GCC uses static_assert
to diagnose the type completeness. MSVC seemingly does not perform such a check. If it silently passes a parameter of std::default_delete::operator()
to delete
, then, this causes undefined behavior. Which might correspond with your observation. It may work, but until it is guaranteed by the documentation (as a non-standard C++ extension), I wouldn't use it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With