如果我使用unique_ptr<T>
构建pimpl类,我理解调用T
析构函数的编译器生成的函数要求T
是完整类型。但是pimpl类的移动构造函数呢?编译器生成的版本只调用unique_ptr
的移动构造函数。该功能不会破坏任何东西。此外,pimpl类生成的移动构造函数是隐式noexcept
,因此它的主体不可能抛出异常,导致它必须退出并销毁{{1}子对象。
似乎应该编译以下代码:
unique_ptr
正如评论所说,所有gcc,clang和MSVC都拒绝此代码。每个人抱怨对不完整类型的操作无效。这是标准要求的吗?如果是这样,那是什么部分?
请注意,此处的问题是编译,因此上述代码由于取消引用null #include <memory>
class Widget { // has implicit move ctor
struct Impl;
std::unique_ptr<Impl> pImpl;
};
int main()
{
Widget *pw1 = nullptr;
new Widget(std::move(*pw1)); // call move ctor. Rejected by
} // gcc, clang, and MSVC
指针而未定义的运行时行为无关紧要。出于同样的原因,在最后一个语句中调用pw1
引起的内存泄漏并不重要。
答案 0 :(得分:5)
如此接近。
此外,pimpl类生成的移动构造函数是 隐含地
noexcept
,所以它的身体不可能抛出 一个例外,会导致它必须退出并销毁unique_ptr
子对象。
在非委托构造函数中,每个潜在的析构函数 可能会调用构造的类类型的子对象(12.4)。 [ 注意:此规定确保在抛出异常时可以为完全构造的子对象调用析构函数(15.2)。 - 结束记录]
这是一个odr-use([basic.def.odr]/3),因此会导致unique_ptr
的析构函数的隐式实例化,而这最终需要一个完整的类型。
noexcept
构造函数没有特殊情况。