is std :: unique_ptr< T>需要知道T的完整定义吗? [英] Is std::unique_ptr<T> required to know the full definition of T?

查看:209
本文介绍了is std :: unique_ptr< T>需要知道T的完整定义吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have some code in a header that looks like this:

#include <memory>

class Thing;

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

如果我在一个不包括 Thing 类型定义,那么这不会在VS2010-SP1下编译:

If I include this header in a cpp that does not include the Thing type definition, then this does not compile under VS2010-SP1:


1> C:\Program Files x86)\Microsoft
Visual Studio
10.0\VC\include\ mememory(2067):error C2027:使用未定义的类型'Thing'

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

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

所以,我猜测它是当前的VS2010 std :: unique_ptr 完全的定义,它完全取决于实现。

So, I'm guessing that it's the current VS2010 std::unique_ptr's implementation that requires the full definition and it's totally implementation-dependant.

还是吗?在它的标准要求中有一些东西使得 std :: unique_ptr 的实现不可能只使用转发声明吗?感觉很奇怪,因为它应该只有一个指针 Thing ,不应该吗?

Or is it? Is there something in it's standard requirements that makes impossible for std::unique_ptr's implementation to work with a forward declaration only? It feels strange as it should only hold a pointer to Thing, shouldn't it?

推荐答案

此处采用。

最多C ++标准库中的模板需要使用完整类型来实例化它们。但 shared_ptr unique_ptr 部分例外。一些,但不是所有的成员可以用不完全类型实例化。这样做的动机是支持使用智能指针的成语,例如 pimpl ,并且不会冒未定义行为的风险。

Most templates in the C++ standard library require that they be instantiated with complete types. However shared_ptr and unique_ptr are partial exceptions. Some, but not all of their members can be instantiated with incomplete types. The motivation for this is to support idioms such as pimpl using smart pointers, and without risking undefined behavior.

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

Undefined behavior can occur when you have an incomplete type and you call delete on it:

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

以上是法定代码。它会编译。编译器可能会或可能不会对上述代码发出警告。当它执行时,坏事可能会发生。如果你很幸运你的程序会崩溃。但是更可能的结果是,您的程序将默认泄漏内存,因为〜A()将不会被调用。

The above is legal code. It will compile. Your compiler may or may not emit a warning for above code like the above. When it executes, bad things will probably happen. If you're very lucky your program will crash. However a more probable outcome is that your program will silently leak memory as ~A() won't be called.

在上面的例子中使用 auto_ptr< A> 没有帮助。你仍然得到相同的未定义的行为,如果你使用一个原始指针。

Using auto_ptr<A> in the above example doesn't help. You still get the same undefined behavior as if you had used a raw pointer.

然而,在某些地方使用不完整的类是非常有用的!这是 shared_ptr unique_ptr 帮助的位置。使用这些智能指针之一将允许您使用不完整的类型,除非有必要有一个完整的类型。最重要的是,当需要一个完整的类型时,如果你尝试使用一个不完整类型的智能指针,那么你会得到一个编译时错误。

Nevertheless, using incomplete classes in certain places is very useful! This is where shared_ptr and unique_ptr help. Use of one of these smart pointers will let you get away with an incomplete type, except where it is necessary to have a complete type. And most importantly, when it is necessary to have a complete type, you get a compile-time error if you try to use the smart pointer with an incomplete type at that point.

没有更多未定义的行为:

如果您的代码已编译,那么您可以随时随地使用完整的类型。

If your code compiles, then you've used a complete type everywhere you need to.

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

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

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

shared_ptr and unique_ptr require a complete type in different places. The reasons are obscure, having to do with a dynamic deleter vs a static deleter. The precise reasons aren't important. In fact, in most code it isn't really important for you to know exactly where a complete type is required. Just code, and if you get it wrong, the compiler will tell you.

但是,如果它对你有帮助,这里是一个表,相对于完整性要求, shared_ptr unique_ptr 如果成员需要完整类型,则条目具有C,否则表格条目用I填充。

However, in case it is helpful to you, here is a table which documents several members of shared_ptr and unique_ptr with respect to completeness requirements. If the member requires a complete type, then entry has a "C", otherwise the table entry is filled with "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

Any operations requiring pointer conversions require complete types for both unique_ptr and shared_ptr.

$ c> unique_ptr< A> {A *} 构造函数可以使用不完整的 A 调用〜unique_ptr< A>()。例如,如果你把 unique_ptr 放在堆上,你可以得到一个不完整的 A 。有关这一点的详细信息,请参见 BarryTheHatchet的答案这里

The unique_ptr<A>{A*} constructor can get away with an incomplete A only if the compiler is not required to set up a call to ~unique_ptr<A>(). For example if you put the unique_ptr on the heap, you can get away with an incomplete A. More details on this point can be found in BarryTheHatchet's answer here.

这篇关于is std :: unique_ptr&lt; T&gt;需要知道T的完整定义吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆