需要知道T的完整定义的ptr <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:使用未定义的类型'Thing'

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

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

或者是? 标准要求中是否有某些东西让std::unique_ptr的实现不可能仅使用前向声明? 这感觉很奇怪,因为它只应该指向Thing ,不是吗?


从这里通过。

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();
    // ...
};

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

但是,如果对您有帮助,这里是一个表格,其中记录了关于完整性要求的shared_ptrunique_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_ptrshared_ptr完整类型。

只有编译器不需要设置对~unique_ptr<A>()的调用时, unique_ptr<A>{A*}构造函数才能脱离A不完整的A 例如,如果你把unique_ptr放在堆上,你可以用一个不完整的A去掉。 关于这一点的更多细节可以在BarryTheHatchet的答案中找到。


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


这不是实现相关的。 它工作的原因是因为shared_ptr决定了在运行时调用的正确的析构函数 - 它不是类型签名的一部分。 然而, unique_ptr的析构函数是它的类型的一部分,并且它必须在编译时被知道。

链接地址: http://www.djcxy.com/p/64193.html

上一篇: ptr<T> required to know the full definition of T?

下一篇: Java servlet: issue with multipart/form