Pimpl with unique_ptr:为什么我必须将接口构造函数的定义移动到“.cpp”?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Pimpl with unique_ptr:为什么我必须将接口构造函数的定义移动到“.cpp”?相关的知识,希望对你有一定的参考价值。

只要我不将构造函数(B)的定义移动到标头B.h,代码就会工作。

B.h

class Imp;  //<--- error here
class B{
    public:
    std::unique_ptr<Imp> imp;
    B();     //<--- move definition to here will compile error
    ~B();
    //// .... other functions ....
};

B.cpp

#include "B.h"
#include "Imp.h"
B::B(){ }
~B::B(){ }

Imp.h

class Imp{};

Main.cpp(编译我)

#include "B.h"

错误:删除指向不完整类型的指针 错误:使用未定义类型'Imp'C2027

我可以以某种方式理解析构函数必须移动到.cpp,因为Imp的结构可能被称为: -

delete pointer-of-Imp;  //something like this

但是,我不明白为什么规则也涵盖了构造函数(问题)。

我读过了 :-

答案

在异常退出的情况下,构造函数需要销毁类成员。

我不认为制作构造函数noexcept会有所帮助,尽管它应该是这样。

另一答案

可以通过以下命令生成b.cpp中的预处理, g++ -E b.cpp >> b.preprocessed 它如下,

# 1 "b.cpp"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "<command-line>" 2
# 1 "b.cpp"
# 1 "b.h" 1

class Imp;

class B
{
    std::unique_ptr< Imp> imp;
public:
    B(){}
    ~B();
};
# 2 "b.cpp" 2
# 1 "imp.h" 1

class Imp
{
};
# 3 "b.cpp" 2

B::~B(){}

在这里可以清楚地看到,class Imp的声明来自构造函数。 那么构造函数如何创建一些不存在的东西呢? (只有前向声明是不够的)并且它清楚地表明构造函数定义必须在b.cpp文件中,以便它将在class Imp声明之后出现并且它变为完整类型。 另一点是,我不认为这是使用疙瘩成语的正确方法。应该在源文件中声明和定义实现类,该文件不能从外部访问,而是将其保存在单独的头文件中。

以上是关于Pimpl with unique_ptr:为什么我必须将接口构造函数的定义移动到“.cpp”?的主要内容,如果未能解决你的问题,请参考以下文章

使用 std::unique_ptr 的 C++ Pimpl Idiom 不完整类型

将使用 PIMPL 习语的类存储在 std::vector 中

C++在使用PImpl技术时,template/typename的不常见用法

pimpl idiom

C++ 设计篇之——pimpl 机制

C++: The PIMPL idiom