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下则没有此现象,仍然和之前提示的一样

具体原理不清楚,期待有人能回答

posted on 2021-11-15 14:41  二十一级厨子  阅读(78)  评论(0编辑  收藏  举报

导航