我在标题中有一些代码,看起来像这样:

#include <memory>

class Thing;

class MyClass
{
    std::unique_ptr< Thing > my_thing;
};

如果我在一个不包括Thing类型定义的cpp中包含这个头,那么这不会在VS2010-SP1下编译:

1>C:\程序文件(x86)\微软 Visual Studio 10.0\VC\include\memory(2067):错误C2027:使用未定义的类型'Thing'

将std::unique_ptr替换为std::shared_ptr并进行编译。

所以,我猜是当前的VS2010 std::unique_ptr的实现需要完整的定义,它完全依赖于实现。

真的是这样吗?它的标准要求中是否有一些东西使得std::unique_ptr的实现不可能只使用前向声明?这感觉很奇怪,因为它应该只持有一个指向Thing的指针,不是吗?


当前回答

简单的答案是使用shared_ptr代替。

其他回答

为了完整起见:

标题:A.h

class B; // forward declaration

class A
{
    std::unique_ptr<B> ptr_;  // ok!  
public:
    A();
    ~A();
    // ...
};

源A.cpp:

class B {  ...  }; // class definition

A::A() { ... }
A::~A() { ... }

类B的定义必须被构造函数、析构函数和任何可能隐式删除B的对象看到。 (虽然构造函数没有出现在上面的列表中,但在VS2017中,即使构造函数也需要b的定义。当考虑到构造函数中的异常情况时,unique_ptr将再次被销毁,这是有意义的。)

我正在寻找一种方法来使用PIMPL习语与std::unique_ptr。这个指南是一个很好的资源。

简而言之,以下是你可以做的事情:

my_class.h

#include <memory>

class Thing;

class MyClass
{
    ~MyClass(); // <--- Added
    std::unique_ptr< Thing > my_thing;
};

my_class.cpp

MyClass::~MyClass() = default; // Or a custom implementation

编译器需要Thing的定义来为MyClass生成默认析构函数。如果显式声明析构函数并将其(空)实现移动到CPP文件,则代码应该被编译。

简单的答案是使用shared_ptr代替。

在模板实例化时需要Thing的完整定义。这就是为什么要编译pimpl习语的确切原因。

如果不可能,人们就不会问这样的问题。