次のコードはVisual Studio(2017と2019の両方で/permissive-)でコンパイルおよびリンクしますが、gccまたはでコンパイルしません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>(); }
私の理解ではで、それであるmain.cpp、Foo::Barその削除を試みているので、完全な型である必要があり~Foo()、暗黙的に宣言されているため、暗黙的にアクセスするすべての翻訳単位で定義されています。
ただし、Visual Studio同意せず、このコードを受け入れます。さらに、次の変更によりVisual Studioコードが拒否されることがわかりました。
- 作る(1)非仮想
- (2)インラインの定義-つまり- Foo() = default;または- Foo(){};
- 削除しています (3)
Visual Studio次の条件で使用されるすべての場所で暗黙のデストラクタが定義されていないように見えます。
- 暗黙のデストラクタは仮想です
- クラスに、別の翻訳単位で定義されたコンストラクターがある
代わりに、2番目の条件のコンストラクターの定義も含む翻訳単位でデストラクターのみを定義しているようです。
だから今私は思っています:
- これは許可されますか?
- これはどこに指定されていますか、それとも少なくともわかってVisual Studioいますか?
更新:バグレポートhttps://developercommunity.visualstudio.com/content/problem/790224/implictly-declared-virtual-destructor-does-not-app.htmlを提出しました。専門家がこれをどうするか見てみましょう。
struct BarDeleter { void operator()(Bar*) const noexcept; };、unique_ptrをに変更しstd::unique_ptr<Bar, BarDeleter> bar_;ます。次に、実装翻訳ユニットに追加しますvoid Foo::BarDeleter::operator()(Foo::Bar* p) const noexcept { try { delete p; } catch(...) {/*discard*/}}