是否需要 std::unique_ptr<T> 才能知道 T 的完整定义?

新手上路,请多包涵

我在标题中有一些代码,如下所示:

 #include <memory>

class Thing;

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

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

1>C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\memory(2067): error C2027: use of undefined type ‘Thing’

std::unique_ptr 替换为 std::shared_ptr 并编译。

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

或者是吗?它的标准要求中是否有某些内容使 std::unique_ptr 的实现无法仅使用前向声明?感觉很奇怪,因为它应该只保存一个指向 Thing 的指针,不是吗?

原文由 Klaim 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1k
2 个回答

这里 采用。

C++ 标准库中的大多数模板都要求使用完整类型对其进行实例化。但是 shared_ptrunique_ptr部分 例外。一些,但不是所有的成员都可以用不完整的类型来实例化。这样做的动机是支持使用智能指针的惯用语,例如 pimpl ,并且不会冒未定义行为的风险。

当您有一个不完整的类型并在其上调用 delete 时,可能会发生未定义的行为:

 class A;
A* a = ...;
delete a;

以上为法典。它会编译。您的编译器可能会也可能不会针对上述代码发出警告。当它执行时,很可能会发生不好的事情。如果你很幸运,你的程序会崩溃。然而,更可能的结果是您的程序将默默地泄漏内存,因为 ~A() 不会被调用。

在上面的示例中使用 auto_ptr<A> 没有帮助。您仍然会得到与使用原始指针相同的未定义行为。

然而,在某些地方使用不完整的类是非常有用的!这是 shared_ptrunique_ptr 帮助的地方。使用这些智能指针之一将使您摆脱不完整的类型,除非需要具有完整的类型。最重要的是,当需要一个完整的类型时,如果您尝试使用具有不完整类型的智能指针,则会出现编译时错误。

不再有未定义的行为

如果您的代码可以编译,那么您在任何需要的地方都使用了完整的类型。

 class A
{
    class impl;
    std::unique_ptr<impl> ptr_;  // ok!

public:
    A();
    ~A();
    // ...
};

unique_ptrshared_ptr 的类型完整性要求

shared_ptrunique_ptr 在不同的地方需要一个完整的类型。原因不明,与动态删除器与静态删除器有关。确切的原因并不重要。事实上,在大多数代码中,确切地知道需要完整类型的位置并不重要。只是代码,如果你弄错了,编译器会告诉你。

但是,如果它对您有帮助,这里有一个表格,其中记录了 shared_ptrunique_ptr 关于完整性要求的几个操作。

手术unique_ptr shared_ptrP() (默认构造函数)_不完整不完整_P(const P&) (复制构造函数) —不完整P(P&&) (移动构造函数)_不完整不完整_~P() (析构函数)完全的不完整P(A*) (来自ptr的构造函数)不完整完全的operator=(const P&) (复制分配) —不完整operator=(P&&) (移动分配)完全的不完整reset()完全的不完整reset(A*)完全的完全的

任何需要指针转换的操作都需要 unique_ptrshared_ptr 的完整类型。

unique_ptr<A>{A*} 构造函数可以摆脱不完整的 A 仅当编译器不需要设置对 ~unique_ptr<A>() 的调用时。例如,如果您将 unique_ptr 放在堆上,则可以避免不完整的 A 。关于这一点的更多细节可以在 BarryTheHatchet 的 回答中 找到

原文由 Howard Hinnant 发布,翻译遵循 CC BY-SA 4.0 许可协议

我正在寻找一种将 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

原文由 Paul 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
logo
Stack Overflow 翻译
子站问答
访问
宣传栏