我正在尝试使用 unique_ptr 作为 pimpl 习惯用法。因此,我在类内部声明了一个析构函数,以便在未定义 impl 类的情况下不会实例化 unique_ptr 删除,然后我在另一个文件中定义它。
这是我的布局:
包装器.h:
#pragma once
#include <memory>
struct Wrapper
{
class Impl;
~Wrapper();
std::unique_ptr<Impl> _impl;
};
包装器.cpp:
#include "wrapper.h"
class Wrapper::Impl {};
Wrapper::~Wrapper() = default;
这个文件编译得很好。
但是,在编译 main.cpp 时,我收到不完整的类型错误(请参阅下面的错误):
主要.cpp:
#include "wrapper.h"
int main()
{
Wrapper w;
return 0;
}
但是,如果我将wrapper.cpp 中的两行添加到main.cpp 的末尾,则它可以正常编译。
我不明白两件事:
- 为什么错误首先会发生?我认为在类中声明析构函数会移动删除调用点?
- 怎么添加代码在最后main.cpp 文件的内容会影响此错误吗?我想“如果使用默认删除器,T必须完整在代码中的点删除器被调用的地方,发生在析构函数中”(来自参考参数 https://en.cppreference.com/w/cpp/memory/unique_ptr).
我缺少什么?
UPDATE:
按照@AdrianMole的建议,我在类Wrapper定义中添加了一个ctor声明,并且由于某种原因它修复了错误,即使错误(和unique_ptr规范)引用了析构函数。
更新了wrapper.h:
struct Wrapper
{
class Impl;
Wrapper();
~Wrapper();
std::unique_ptr<Impl> _impl;
};
所以我补充一个问题:
- 为什么添加构造函数声明可以解决这个问题?
这些是我在 MSVC 中遇到的错误,但在 clang 或 gcc 中也会出现类似的错误(我尝试过在线编译器):
内存(2536,1):错误C2027:使用未定义类型“Wrapper::Impl”
wrapper.h(7): message : 请参阅“Wrapper::Impl”的声明
内存(2535):消息:编译类模板成员函数'void std::default_deleteWrapper::Impl::operator ()(_Ty *) noexcept const'
with
[
_Ty=Wrapper::Impl
]
内存(2647):消息:请参阅正在编译的函数模板实例化“void std::default_deleteWrapper::Impl::operator ()(_Ty *) no except const”的引用
with
[
_Ty=Wrapper::Impl
]
内存(2574):消息:请参阅正在编译的类模板实例化“std::default_deleteWrapper::Impl”的引用
wrapper.h(9): message : 请参阅正在编译的类模板实例化 'std::unique_ptrWrapper::Impl,std::default_delete<:impl>' 的引用
内存(2536,25):错误C2338:无法删除不完整的类型
内存(2537,1):警告C4150:删除指向不完整类型“Wrapper::Impl”的指针;没有调用析构函数
wrapper.h(7): message : 请参阅“Wrapper::Impl”的声明