为何std::unique_ptr<不完全类型>带{nullptr}初始化会编译失败?
std::unique_ptr类内{nullptr}初始化导致不完全类型编译错误的原因
我原本有一段代码编译失败,一开始以为必须给std::unique_ptr<AA>定义自定义删除器才能解决,但后来通过两个修改让代码正常运行:
- 在BB.cpp中显式实现默认构造函数(避免编译器生成隐式的类内默认构造);
- 移除
std::unique_ptr<AA>的{nullptr}类内初始化器。
已知std::default_deleter<AA>允许在AA为不完全类型时实例化,想请教为什么{nullptr}这个类内初始化会导致代码失效?
代码示例
BB.h
#include <memory> struct AA; struct BB { // BB(); <- 显式声明后需在BB.cpp中定义 ~BB(); std::unique_ptr<AA> u{ nullptr }; // 移除这个{nullptr}初始化器即可编译通过 };
BB.cpp
#include "BB.h" struct AA {}; BB::~BB() = default; // BB::BB() = default; <- 显式定义默认构造函数后也可编译通过
main.cpp
#include "BB.h" int main() { BB bb{}; }
问题原因解析
核心在于类内成员初始化器对隐式默认构造函数实例化时机的影响:
当给
std::unique_ptr<AA> u添加{nullptr}类内初始化器时,若BB没有用户声明的构造函数,编译器会生成inline的隐式默认构造函数。这个构造函数的定义会在每个调用它的翻译单元中实例化——也就是在main.cpp里,而此时AA仍然是不完全类型(仅前向声明,未定义)。尽管
std::default_deleter<AA>的实例化允许AA为不完全类型,但用{nullptr}初始化unique_ptr<AA>的过程,会在隐式构造函数实例化时触发对unique_ptr<AA>模板的额外检查。这些检查在AA不完全的语境下无法完成,导致编译器报错。而当移除类内初始化器,或者在BB.cpp中显式定义默认构造函数(此时
AA已经是完整类型),unique_ptr<AA>的初始化会在AA类型完整的语境下完成,所有模板检查都能正常通过,自然不会有编译错误。
内容的提问来源于stack exchange,提问作者Tom Huntington
相关产品推荐
相关产品推荐

