来自here。
C++ 标准库中的大多数模板都要求使用完整类型对其进行实例化。但是shared_ptr 和unique_ptr 是部分 例外。一些,但不是所有的成员都可以用不完整的类型来实例化。这样做的动机是使用智能指针支持 pimpl 等惯用语,并且不会冒未定义行为的风险。
当您有一个不完整的类型并在其上调用delete 时,可能会发生未定义的行为:
class A;
A* a = ...;
delete a;
以上为合法代码。它会编译。您的编译器可能会也可能不会针对上述代码发出警告。当它执行时,很可能会发生不好的事情。如果你很幸运,你的程序会崩溃。然而,更可能的结果是您的程序将默默地泄漏内存,因为不会调用 ~A()。
在上面的例子中使用auto_ptr<A> 没有帮助。您仍然会得到与使用原始指针相同的未定义行为。
尽管如此,在某些地方使用不完整的类是非常有用的!这是shared_ptr 和unique_ptr 提供帮助的地方。使用这些智能指针之一将使您摆脱不完整的类型,除非需要具有完整的类型。最重要的是,当需要一个完整的类型时,如果你尝试使用具有不完整类型的智能指针,则会出现编译时错误。
不再有未定义的行为:
如果您的代码可以编译,那么您在任何需要的地方都使用了完整的类型。
class A
{
class impl;
std::unique_ptr<impl> ptr_; // ok!
public:
A();
~A();
// ...
};
shared_ptr 和 unique_ptr 在不同的地方需要一个完整的类型。原因不明,与动态删除器与静态删除器有关。确切的原因并不重要。事实上,在大多数代码中,确切地知道需要完整类型的位置并不重要。只是代码,如果你写错了,编译器会告诉你的。
但是,如果对您有帮助,这里有一个表格,其中记录了 shared_ptr 和 unique_ptr 的几个成员关于完整性要求的内容。如果成员需要一个完整的类型,那么条目有一个“C”,否则表格条目用“I”填充。
Complete type requirements for unique_ptr and shared_ptr
unique_ptr shared_ptr
+------------------------+---------------+---------------+
| P() | I | I |
| default constructor | | |
+------------------------+---------------+---------------+
| P(const P&) | N/A | I |
| copy constructor | | |
+------------------------+---------------+---------------+
| P(P&&) | I | I |
| move constructor | | |
+------------------------+---------------+---------------+
| ~P() | C | I |
| destructor | | |
+------------------------+---------------+---------------+
| P(A*) | I | C |
+------------------------+---------------+---------------+
| operator=(const P&) | N/A | I |
| copy assignment | | |
+------------------------+---------------+---------------+
| operator=(P&&) | C | I |
| move assignment | | |
+------------------------+---------------+---------------+
| reset() | C | I |
+------------------------+---------------+---------------+
| reset(A*) | C | C |
+------------------------+---------------+---------------+
任何需要指针转换的操作都需要unique_ptr 和shared_ptr 的完整类型。
仅当编译器不需要设置对~unique_ptr<A>() 的调用时,unique_ptr<A>{A*} 构造函数才能摆脱不完整的A。例如,如果您将unique_ptr 放在堆上,则可以使用不完整的A。关于这一点的更多细节可以在BarryTheHatchet's答案here找到。