[英]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:
- T具有无法销毁的非静态数据成员(已删除或无法访问的销毁器)
- T具有无法销毁的直接或虚拟基类(已删除或无法访问的销毁器)
- T是一个并集,并且具有带有非平凡析构函数的变体成员。
- 隐式声明的析构函数是虚拟的(因为基类具有虚拟的析构函数),并且对释放函数的查找(运算符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(); }
有关上述代码的一些注意事项:
A
和C
暴露给我的库的使用者,并使B
内部保留。 您必须在定义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.