Effective Modern C++ Item 22 适用Pimpl习惯用法时,将特殊成员函数的定义放到实现文件中(问题记录)
今天读到 Effective Modern C++中 Item 22所述,使用unique_ptr来创建并持有 pImpl 结构,对其中的一个问题做一些记录,具体的条款内容就不再描述,随便搜索或者参考如下链接:
https://blog.csdn.net/aiyanzielf/article/details/107790273
根据书中的描述首先做了实验,确实是如文中所述,必须显示的在cpp文件中定义析构才可以通过编译,即需要让析构看见完整的Impl类型
否则都会发生static_assert(0 < sizeof(_Ty)错误,即使用了不完整的类型
//--------------------------ImplTest.h-------------------------- #include <memory> class Impl; class ImplTest { public: ImplTest(); // ~ImplTest(); //@1 不定义 wrong ~ImplTest(){}; //@2 空定义 wrong ~ImplTest() = default; //@3 默认定义 wrong ~ImplTest(); //@4 声明后在cpp中定义 ok private: std::unique_ptr<Impl> p_impl_; }; //--------------------------ImplTest.cpp-------------------------- #include "ImplTest.h" #include <iostream> class Impl { public: Impl() {}; ~Impl() { std::cout << "Destroy impl" << std::endl; }; }; ImplTest::ImplTest() { p_impl_ = std::make_unique<Impl>(); } ImplTest::~ImplTest() = default; //对于@4,在cpp中定义 ok
int main(int argc, char** argv)
{
auto uptr = std::make_unique<ImplTest>();
ImplTest itest;
ImplTest* pim = new ImplTest(); //注意,如果不写下一行的delete是ok的,因为此时没涉及到调用析构函数
delete pim;
return 0;
}
但是有一个问题就是在msvc下当ImplTest类是继承自具有虚析构函数的父类时,问题消失了,代码如下:
#include <memory> class ImplAnce { public: ImplAnce() {}; virtual ~ImplAnce() {}; }; class Impl; class ImplTest:public ImplAnce { public: ImplTest(); // ~ImplTest(); // Ok,不写析构函数
~ImplTest() = default; //Ok,使用默认
std::unique_ptr<Impl> p_impl_; };
即不进行析构函数的声明,使用默认的即可,并且也不需要在cpp中定义析构函数。但是在gcc下则没有此现象,仍然和之前提示的一样
具体原理不清楚,期待有人能回答