从这里通过。
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>{A*}构造可以逃脱不完整A仅如果不需要编译器建立一个呼叫~unique_ptr<A>()。例如,如果将unique_ptron放在堆上,则可以通过incomplete来解决A。关于这一点的更多详细信息可以在BarryTheHatchet的答案中找到。
               
              
shared_ptrunique_ptr不需要完整类型的最好解释是Howard Hinnant的“ Incomplete types and / ” ,末尾的表应该回答您的问题。