C++ 中的 pImpl 模式需要 impl 子类的完整定义

Gar*_*ryO 1 c++ pimpl-idiom

我已经查看了许多关于 pImpl、unique_ptr 和前向声明的 SO 问题,但无法找出问题所在。答案是std::unique_ptr<T> 需要知道 T 的完整定义吗?看起来很完整,但我不知道如何将其应用到我的情况。

我在https://wandbox.org/permlink/9joq3PnkEZ6j8TI8有一个简单的 pImpl 模式。主类包含 impl 类的 unique_ptr,它管理一些资源,因此它具有自定义构造函数/析构函数。我正在使用带有 clang 14 的 C++20(在 MacOS 上,确实如此,但在上面的 wandbox 中也发生了同样的错误)。

编译它会出现可怕的“对不完整类型无效应用‘sizeof’”错误。

代码是这样的:

// testclass.h
#include <experimental/propagate_const>

// Main class with a pImpl pattern -- impl class is incomplete here.
class Main {
  public:
    void main_f();
    Main();
  private:
    class impl;
    std::experimental::propagate_const<std::unique_ptr<impl>> pImpl;
};
Run Code Online (Sandbox Code Playgroud)
// testclass.cpp
#include "testclass.h"

// Implementation of Main with its impl

class Main::impl {
  private:
    int foo;
 public:
  impl() = default;
  ~impl() {
    cout << "bye from impl";
  };
  impl(const impl &) = delete;
  impl &operator=(const impl &other) = delete;
  impl(impl &&source) noexcept = default;
  impl &operator=(impl &&other) noexcept = default;
}

// To construct a Main, construct a unique pointer to a new impl
Main::Main() : pImpl{std::make_unique<impl>()} {}
Run Code Online (Sandbox Code Playgroud)

和主要:

// main.cpp
#include "testclass.h"
int main() { 
    Main main;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

有人能指出我正确的方向吗?

Hol*_*Cat 6

您需要~Main();在类中声明析构函数,并在 .cpp 文件中定义它。

那是因为它的定义需要impl完整,而现在它在创建时被隐式定义Main main;,并且impl不完整。

您可能希望对移动操作执行相同的操作,因为由于自定义析构函数,它们不会自动定义。