我正在尝试将 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;
}
但是,如果我在 main.cpp 的末尾添加 wrapper.cpp 中的两行,它编译得很好。我不明白两件事:
我错过了什么?
更新:
按照@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 *) noexcept const”的引用
with [ _Ty=Wrapper::Impl ]
内存(2574):消息:请参阅对正在编译的类模板实例化“std::default_deleteWrapper::Impl”的引用
wrapper.h(9):消息:请参阅对正在编译的类模板实例化 'std::unique_ptrWrapper::Impl,std::default_delete<Wrapper::Impl>' 的引用
内存(2536,25):错误 C2338:无法删除不完整的类型
内存(2537,1):警告 C4150:删除指向不完整类型“Wrapper::Impl”的指针;没有调用析构函数
wrapper.h(7): message : 见'Wrapper::Impl'的声明
任何构造函数定义(包括隐式定义的默认构造函数)都可能调用类类型的所有成员对象的类型的析构函数。这样做的基本原理是,如果构造后面的成员抛出异常,则需要调用所有先前成员的析构函数。对于最后一个成员,这不是严格要求的,但标准没有例外。
例如,如果您的课程是:
struct complete_type_with_throwing_constructor {
complete_type_with_throwing_constructor() { throw 0; }
};
struct Wrapper
{
class Impl;
~Wrapper();
std::unique_ptr<Impl> _impl;
complete_type_with_throwing_constructor x;
};
然后隐式默认构造函数Wrapper
will 构造_impl
然后在x
throws的默认构造函数之后销毁它。
如果您显式声明默认构造函数,这就是您的代码工作的原因。这将定义移动到std::unique_ptr<Impl>
可以实例化的析构函数的点。
至于你的第二个问题,你是对的,之后添加定义时代码仍然不能工作。只是编译器没有检测到它,所以他们没有错误。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句