基于unique_ptr的pimpl类中的move构造函数是否需要完整类型?

时间:2016-01-09 05:43:00

标签: c++ c++11 unique-ptr move-constructor

如果我使用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引起的内存泄漏并不重要。

1 个答案:

答案 0 :(得分:5)

如此接近。

  

此外,pimpl类生成的移动构造函数是   隐含地noexcept,所以它的身体不可能抛出   一个例外,会导致它必须退出并销毁   unique_ptr子对象。

[class.base.init]/12

  

在非委托构造函数中,每个潜在的析构函数   可能会调用构造的类类型的子对象(12.4)。 [   注意:此规定确保在抛出异常时可以为完全构造的子对象调用析构函数(15.2)。    - 结束记录]

这是一个odr-use([basic.def.odr]/3),因此会导致unique_ptr的析构函数的隐式实例化,而这最终需要一个完整的类型。

noexcept构造函数没有特殊情况。