我在标题中有一些代码,如下所示:
#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 许可协议
从 这里 采用。
C++ 标准库中的大多数模板都要求使用完整类型对其进行实例化。但是
shared_ptr
和unique_ptr
是 部分 例外。一些,但不是所有的成员都可以用不完整的类型来实例化。这样做的动机是支持使用智能指针的惯用语,例如 pimpl ,并且不会冒未定义行为的风险。当您有一个不完整的类型并在其上调用
delete
时,可能会发生未定义的行为:以上为法典。它会编译。您的编译器可能会也可能不会针对上述代码发出警告。当它执行时,很可能会发生不好的事情。如果你很幸运,你的程序会崩溃。然而,更可能的结果是您的程序将默默地泄漏内存,因为
~A()
不会被调用。在上面的示例中使用
auto_ptr<A>
没有帮助。您仍然会得到与使用原始指针相同的未定义行为。然而,在某些地方使用不完整的类是非常有用的!这是
shared_ptr
和unique_ptr
帮助的地方。使用这些智能指针之一将使您摆脱不完整的类型,除非需要具有完整的类型。最重要的是,当需要一个完整的类型时,如果您尝试使用具有不完整类型的智能指针,则会出现编译时错误。不再有未定义的行为
如果您的代码可以编译,那么您在任何需要的地方都使用了完整的类型。
unique_ptr
和shared_ptr
的类型完整性要求shared_ptr
和unique_ptr
在不同的地方需要一个完整的类型。原因不明,与动态删除器与静态删除器有关。确切的原因并不重要。事实上,在大多数代码中,确切地知道需要完整类型的位置并不重要。只是代码,如果你弄错了,编译器会告诉你。但是,如果它对您有帮助,这里有一个表格,其中记录了
shared_ptr
和unique_ptr
关于完整性要求的几个操作。手术unique_ptr shared_ptr
P()
(默认构造函数)_不完整不完整_P(const P&)
(复制构造函数) —不完整P(P&&)
(移动构造函数)_不完整不完整_~P()
(析构函数)完全的不完整P(A*)
(来自ptr的构造函数)不完整完全的operator=(const P&)
(复制分配) —不完整operator=(P&&)
(移动分配)完全的不完整reset()
完全的不完整reset(A*)
完全的完全的任何需要指针转换的操作都需要
unique_ptr
和shared_ptr
的完整类型。unique_ptr<A>{A*}
构造函数可以摆脱不完整的A
仅当编译器不需要设置对~unique_ptr<A>()
的调用时。例如,如果您将unique_ptr
放在堆上,则可以避免不完整的A
。关于这一点的更多细节可以在 BarryTheHatchet 的 回答中 找到。