Đoạn mã sau sẽ biên dịch và liên kết với Visual Studio
(cả 2017 và 2019 với /permissive-
), nhưng không biên dịch với một trong hai gcc
hoặc 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>(); }
Sự hiểu biết của tôi là, trong main.cpp
, Foo::Bar
phải là một loại hoàn chỉnh, bởi vì việc xóa nó được cố gắng ~Foo()
, được khai báo ngầm và do đó được định nghĩa ngầm trong mọi đơn vị dịch thuật truy cập nó.
Tuy nhiên, Visual Studio
không đồng ý và chấp nhận mã này. Ngoài ra, tôi thấy rằng các thay đổi sau đây sẽ Visual Studio
từ chối mã:
- Làm cho
(1)
không ảo - Xác định
(2)
nội tuyến - tức làFoo() = default;
hoặcFoo(){};
- Đang gỡ bỏ
(3)
Nó trông như thể Visual Studio
tôi không định nghĩa một hàm hủy ngầm ẩn ở mọi nơi nó được sử dụng theo các điều kiện sau:
- Hàm hủy ngầm định là ảo
- Lớp này có một hàm tạo được định nghĩa trong một đơn vị dịch khác
Thay vào đó, nó dường như chỉ định nghĩa hàm hủy trong đơn vị dịch cũng chứa định nghĩa cho hàm tạo trong điều kiện thứ hai.
Vì vậy, bây giờ tôi đang tự hỏi:
- Điều này có được phép không?
- Nó được chỉ định ở bất cứ đâu, hoặc ít nhất được biết, đó là
Visual Studio
điều này?
Cập nhật: Tôi đã gửi báo cáo lỗi https://developercommunity.visualstudio.com/content/probols/790224/implictly-declared-virtual-destructor-does-not-app.html . Hãy xem những gì các chuyên gia làm về điều này.
struct BarDeleter { void operator()(Bar*) const noexcept; };
và thay đổi unique_ptr thành std::unique_ptr<Bar, BarDeleter> bar_;
. Sau đó, trong đơn vị dịch thuật triển khai, hãy thêm vàovoid Foo::BarDeleter::operator()(Foo::Bar* p) const noexcept { try { delete p; } catch(...) {/*discard*/}}