繁体   English   中英

为什么在使用PIMPL习惯用法时此类型不完整?

[英]Why is this type incomplete when using the PIMPL idiom?

我使用PIMPL方法,具体我使用所提供的范本这个职位 给定下面的类集并使用VS2015 Update 3进行编译,我遇到了编译错误:

错误C2027使用未定义类型'C :: C_impl'(编译源文件src \\ A.cpp)

错误C2338无法删除不完整的类型(编译源文件src \\ A.cpp)

警告C4150删除了指向不完整类型'C :: C_impl'的指针; 没有调用析构函数(编译源文件src \\ A.cpp)

我可以通过取消注释C::~C() 〜C C::~C()来解决此问题,这使我相信某些原因阻止了~C()自动生成,但我不知道是什么。 根据此参考 ,如果满足以下任一条件,则将类型T的析构函数隐式定义为delete:

  1. T具有无法销毁的非静态数据成员(已删除或无法访问的销毁器)
  2. T具有无法销毁的直接或虚拟基类(已删除或无法访问的销毁器)
  3. T是一个并集,并且具有带有非平凡析构函数的变体成员。
  4. 隐式声明的析构函数是虚拟的(因为基类具有虚拟的析构函数),并且对释放函数的查找(运算符delete()导致对模糊,删除或不可访问的函数的调用)。

项#2、3和4显然不适用于C ,并且我不认为#1适用,因为pimpl<>C的唯一成员)显式定义了析构函数。

有人可以解释发生了什么吗?

#pragma once
#include <Pimpl.h>

class A
{
private:
    struct A_impl;
    pimpl<A_impl> m_pimpl;
};

BH

#pragma once
#include "C.h"

class B
{
private:
    C m_C;
};

#pragma once
#include <Pimpl.h>

class C
{
public:
    // Needed for the PIMPL pattern
    //~C();

private:
    struct C_impl;
    pimpl<C_impl> m_pimpl;
};

A.cpp

#include <memory>
#include "A.h"
#include "B.h"
#include <PimplImpl.h>

struct A::A_impl
{
    std::unique_ptr<B> m_pB;
};

// Ensure all the code for the template is compiled
template class pimpl<A::A_impl>;

C.cpp

#include <C.h>
#include <PimplImpl.h>

struct C::C_impl { };

// Needed for the PIMPL pattern
//C::~C() = default;

// Ensure all the code for the template is compiled
template class pimpl<C::C_impl>;

为了完整起见,以上引用的帖子中的PIMPL实现:

pimpl.h

#pragma once
#include <memory>

template<typename T>
class pimpl
{
private:
    std::unique_ptr<T> m;
public:
    pimpl();
    template<typename ...Args> pimpl(Args&& ...);
    ~pimpl();
    T* operator->();
    T& operator*();
};

PimplImpl.h

#pragma once
#include <utility>

template<typename T>
pimpl<T>::pimpl() : m{ new T{} } {}

template<typename T>
template<typename ...Args>
pimpl<T>::pimpl(Args&& ...args)
    : m{ new T{ std::forward<Args>(args)... } }
{
}

template<typename T>
pimpl<T>::~pimpl() {}

template<typename T>
T* pimpl<T>::operator->() { return m.get(); }

template<typename T>
T& pimpl<T>::operator*() { return *m.get(); }

有关上述代码的一些注意事项:

  • 我试图将AC暴露给我的库的使用者,并使B内部保留。
  • 这里没有B.cpp,那就是empy。

您必须在定义C :: C_impl之后手动定义C析构函数,因为默认情况下,编译器会尝试在使用时生成C析构函数,但是可能会在找不到C :: C_impl定义的地方(例如,可以B.cpp)。

我认为问题在于std::unique_ptr需要在实例化时知道销毁函数(即析构函数)。

与默认析构函数~C()编译器在使用的点产生的,这意味着它试图删除pimpl<C_impl>与提供给它的信息对象A.cpp 当然,由于仅在那时声明C_impl ,所以编译器不知道如何销毁C_impl对象,这就是您收到的错误。

取消注释〜C ~C(); 告诉编译器不要担心如何销毁将在其他地方定义的C_impl 在您的情况下,在C.cpp中定义了C_impl的定义。

响应于您的编辑,析构函数为pimpl<C_impl>具有std::unique_ptr<C_impl>其具有与不可访问的析构函数的非静态数据成员( C_impl是在使用的点withing不完全类型A.cpp )。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM