C ++中各种智能指针之间的转换规则是什么?

时间:2010-11-21 08:44:47

标签: c++ rules smart-pointers

TR1引入了shared_ptr,weak_ptr,scoped_ptr和unique_ptr等。

我想知道这些类型之间的各种转换/类型提升规则。

例如,当scoped_ptr被分配给shared_ptr时会发生什么?这种转换是否可行/有意义以及此类转换的用例是什么?

(具体中是否有表格?)

3 个答案:

答案 0 :(得分:12)

首先,对您的问题进行一些更正:

  • scoped_ptr是Boost的一部分,不包含在C ++ TR1或C ++ 0x中(预计在C ++ 0x unique_ptr中可以使用{{1}传统上一直使用)。

  • scoped_ptr不是C ++ TR1的一部分;它是C ++ 0x的一部分(因为它依赖于rvalue引用和移动语义,它们仅在C ++ 0x中可用)。

要回答您的问题:unique_ptrshared_ptr齐头并进。 weak_ptr所拥有的对象也可以由shared_ptr引用。它们是互补的。

weak_ptr拥有其管理的对象的唯一所有权;没有其他人可以拥有该对象的所有权。这与unique_ptr的所有权语义相反:使用shared_ptr,您拥有非共享的唯一所有权;使用unique_ptr您拥有共享的,非唯一的所有权。

您可以从shared_ptr构建shared_ptr;执行此操作时,unique_ptr将失去对象的所有权。这是有效的,因为您始终知道给定的unique_ptr始终是对象的唯一所有者,因此它能够释放该所有权。

一旦对象归unique_ptr所有,您就无法释放该对象的所有权,因为无法保证给定的shared_ptr是该对象的唯一所有者。

答案 1 :(得分:3)

给定两个类AB(可能是智能指针类型),有四种主要方法可以将B类型的实例转换为类型A

  • AB的可访问基类对象(例如B是从A公开派生的),转换可以切片或者只是调整引用或指针的类型。(故意删除)。

  • A有一个可访问的构造函数,其中包含B

  • B有一个可访问的转换运算符,生成A

  • 存在一些函数需要B并生成A,并且您正在调用该函数。

对于智能指针,继承不用于促进转换,因为继承允许不正确的转换;因此上面的罢工。例如,如果SmartPtr<Derived>SmartPtr<Base>公开继承,则可以SmartPtr<Base>& spBase = spDerived;进行spBase = spOtherDerived,然后例如const,这会有相当大的问题......在适当高的抽象层次上,这与针对指针转换的auto_ptr基本相同;请参阅常见问题解答18.17 "Why am I getting an error converting a Foo** → Foo const**?"

因此,智能指针转换通常通过最后三个要点表示,即构造函数,转换运算符和命名转换函数。

基本上C ++ 0x中有三个智能指针,忽略了已弃用的std::unique_ptr

    单个对象的
  • std::unique_ptr

  • 数组
  • std::shared_ptr

  • 单个对象的
  • unique_ptr

auto_ptr表达所有权转移,正如旧auto_ptr所做的那样。但unique_ptr不支持数组。 unique_ptr会这样做,这会影响可能的转化。

对于单个对象,unique_ptr通过构造函数支持相应原始指针所做的转换。它有一个带有unique_ptr其他类型的模板化构造函数。参见例如C ++ 0x草案N3126§20.9.10.2。

但是,对于那些与原始指针一样危险的数组!因此,对于数组unique_ptr提供基本/派生转换。参见例如C ++ 0x草案N3126§20.9.10.3。

由于shared_ptr表达了所有权转移,而shared_ptr表达了共享所有权,因此无法从unique_ptrshared_ptr进行安全的常规转换。但是,另一方面,Boost auto_ptr有一个构造函数取shared_ptr,而C ++ 0x unique_ptr保留了这个(也有它)并自然地添加一个构造函数{{1 }}。参见C ++ 0x draftN3126§20.9.11.2/ 1。

shared_ptr通过构造函数和概念上实现“强制转换”的自由函数提供基本/派生转换。从本质上讲,这意味着shared_ptr直接用于类类型对象的数组非常危险。为此,请将其包裹起来。

如上所述,从shared_ptr转换为unique_ptr不支持作为一般操作。因为共享所有权与所有权转移不直接兼容。但是,无视复杂性。线程安全,shared_ptr::unique告诉您是否有单一所有者(即您的实例),然后,如果您具有如何构建初始shared_ptr的必要知识,您可以使用自由函数get_deleter来获取指向删除函数的指针,并执行一些低级别的恶作剧。如果你完全理解我在这里所说的话,那么很好,很好。如果没有,那么我最好不要提供更多细节,因为这是一个非常特殊的案例,它需要非常小心,而且你真的知道你在做什么。 ; - )

嗯,就是这样。我不是在讨论weak_ptr,因为它只是shared_ptr功能的一部分。但希望以上就是你所要求的。

答案 2 :(得分:2)

  1. scoped_ptr AFAIK不属于TR1(如果我错了,请纠正我)。通常boost的{​​{1}}根本无法转让所有权。指定指针后,就无法释放它。
  2. scoped_ptr只能使用unique_ptr转让所有权,因此也不会转让所有权。
  3. std::move无法释放所有权,因为其他指针可能与之共享。它可以转换为shared_ptr。如果你试图从weak_ptr转换它并且对象被释放它会抛出。
  4. weak_ptr可以从weak_ptr创建,转换为shared_ptr时,如果该对象不再存在,它可能会抛出。