Pimpl
(Pointer to implementation)很多同学都不陌生,但是从原始指针升级到C++11的独占指针std::unique_ptr
时,会遇到一个incomplete type
的报错,本文来分析一下报错的原因以及分享几种解决方法~
问题现象
首先举一个传统C++中的Pimpl
的例子
// widget.h
// 预先声明
class Impl;
class Widget
{
Impl * pImpl;
};
很简单,没什么问题,但是使用的是原始指针,现在我们升级到std::unique_ptr
// widget.h
// 预先声明
class Impl;
class Widget
{
std::unique_ptr<Impl> pImpl;
};
很简单的一次升级,而且也能通过编译,看似也没问题,但当你创建一个Widget
的实例
// pimpl.cpp
#include "widget.h"
Widget w;
这时候,问题来了
$ g++ pimpl.cpp
In file included from /usr/include/c++/9/memory:80,
from widget.h:1,
from pimpl.cpp:1:
/usr/include/c++/9/bits/unique_ptr.h:
In instantiation of ‘void std::default_delete<_Tp>::operator()(_Tp*) const [with _Tp = Impl]’:
/usr/include/c++/9/bits/unique_ptr.h:292:17:
required from ‘std::unique_ptr<_Tp, _Dp>::~unique_ptr() [with _Tp = Impl; _Dp = std::default_delete<Impl>]’
widget.h:5:7: required from here
/usr/include/c++/9/bits/unique_ptr.h:79:16: error: invalid application of ‘sizeof’ to incomplete type ‘Impl’
79 | static_assert(sizeof(_Tp)>0,
| ^~~~~~~~~~~
原因分析
从报错我们可以看出,std::unique_ptr
中需要静态检测类型的大小static_assert(sizeof(Impl)>0
,但是我们的Impl
是一个预先声明的类型,是incomplete type
,也就没法计算,所以导致报错。
想要知道怎么解决,首先需要知道std::unique_ptr
为啥需要计算这个,我们来看一下STL中相关的源码,从报错中得知是unique_ptr.h
的292行,调用了79行,我们把前后相关源码都粘出来(来自g++ 9.3.0
中的实现)