unique_ptr-based pimpl class 中的移动构造函数是否需要完整类型?

Does the move constructor in a unique_ptr-based pimpl class require a complete type?

如果我使用 unique_ptr<T> 构建一个 pimpl class,我知道编译器生成的函数调用 T 的析构函数需要 T 是一个完整类型。但是 pimpl class 的移动构造函数呢?编译器生成的版本只调用 unique_ptr 的移动构造函数。该功能不会破坏任何东西。此外,pimpl class 生成的移动构造函数是隐式的 noexcept,因此它的主体不可能抛出异常,导致它不得不退出并销毁 unique_ptr 子对象.

似乎应该编译以下代码:

#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

如评论所述,此代码被所有 gcc、clang 和 MSVC 拒绝。每个人都抱怨对不完整类型的无效操作。这是标准要求的吗?如果有,是哪一部分?

请注意,这里的问题是编译,因此上述代码由于取消引用空 pw1 指针而导致的未定义运行时行为是无关紧要的。同理,最后一条语句中调用new产生的内存泄漏并不重要。

这么近。

Furthermore, the pimpl class's generated move constructor is implicitly noexcept, so there's no possibility of its body throwing an exception that would cause it to have to back out and destroy the unique_ptr subobject.

[class.base.init]/12:

In a non-delegating constructor, the destructor for each potentially constructed subobject of class type is potentially invoked (12.4). [ Note: This provision ensures that destructors can be called for fully-constructed sub-objects in case an exception is thrown (15.2). —end note ]

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

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