【问题标题】:Does C++11 unique_ptr and shared_ptr able to convert to each other's type?C++11 unique_ptr 和 shared_ptr 是否能够转换为彼此的类型?
【发布时间】:2016-10-19 11:28:41
【问题描述】:

C++11 标准库是否提供从std::shared_ptr 转换为std::unique_ptr 的实用程序,反之亦然?这样操作安全吗?

【问题讨论】:

  • 请定义“安全操作”。你在寻找什么样的安全?终生管理安全?线程安全?
  • "STL" 并不意味着标准库。 STL 与shared_ptr 无关。
  • @jaggedSpire 线程安全意味着您在不同线程中使用了所有者,即使用次数不是 1。
  • @curiousguy 我知道。我的观点是 OP 的问题没有很好地定义“安全”,他需要澄清他的意思是哪种“安全”,因为有多种。

标签: c++ c++11 shared-ptr unique-ptr


【解决方案1】:

std::unique_ptr 是 C++11 表达独占所有权的方式,但它的一种 最吸引人的特点是它可以轻松高效地转换为std::shared_ptr

这是为什么std::unique_ptr 非常适合作为工厂函数返回类型的关键部分。工厂函数无法知道调用者是否希望对它们返回的对象使用独占所有权语义,或者共享所有权(即std::shared_ptr)是否更合适。通过返回 std::unique_ptr,工厂为调用者提供了最有效的智能指针,但它们不会妨碍调用者用更灵活的兄弟替换它。

std::shared_ptrstd::unique_ptr 是不允许的。一旦您将资源的生命周期管理移交给std::shared_ptr,您就不会改变主意。即使引用计数为 1,您也无法收回资源的所有权,以便让 std::unique_ptr 管理它。

参考:有效的现代 C++。改进 C++11 和 C++14 使用的 42 种特定方法。斯科特迈耶斯。

简而言之,您可以轻松高效地将std::unique_ptr 转换为std::shared_ptr,但您无法将std::shared_ptr 转换为std::unique_ptr

例如:

std::unique_ptr<std::string> unique = std::make_unique<std::string>("test");
std::shared_ptr<std::string> shared = std::move(unique);

或:

std::shared_ptr<std::string> shared = std::make_unique<std::string>("test");

【讨论】:

  • 请注意,如果您不小心(例如通过更改成员变量)将std::unique_ptr 分配给std::shared_ptr
  • @StefanQ 是什么让您认为不允许将std::unique_ptr 分配给std::shared_ptr?标准库为std::shared_ptr&lt;T&gt; 定义了一个移动赋值运算符template&lt;class Y, class Deleter&gt; shared_ptr&amp; operator=(std::unique_ptr&lt;Y, Deleter&gt;&amp;&amp; r);
  • 我想强调从unique_ptrshared_ptr 的转换是有效的,因为shared_ptr 类知道unique_ptr,并且它配备了接受@987654347 的构造函数和赋值运算符@ 到 unique_ptr (右值引用是必不可少的,因为保证 unique_ptr 不会再被使用)。创造魔法的不是std::move,而是shared_ptr类。
【解决方案2】:

我更愿意这样做。

std::unique_ptr<int> up_ = std::make_unique<int>();
std::shared_ptr<int> sp_ = std::move(up_);

【讨论】:

    【解决方案3】:

    给定 unique_ptr u_ptr,创建 shared_ptr s_ptr:

    std::shared_ptr<whatever> s_ptr(u_ptr.release());
    

    走另一条路是不切实际的。

    【讨论】:

    • 这是“正确”的方式:std::shared_ptr&lt;whatever&gt; s_ptr(std::move(u_ptr));
    • 这里是迂腐的“正确”方式:std::shared_ptr&lt;whatever&gt; s_ptr{std::move(u_ptr)};
    • 它有什么不安全的地方?
    • @VioletGiraffe • 我想polyvertex 提倡使用新的初始化列表语法——它避免了无声的缩小转换并以统一的语法适应成员初始化——这是一个很好的习惯。六个中的一个,六个另一个?
    • @nmr 这是不安全的,因为您可能会丢失存储在unique_ptr 中的Deleter
    猜你喜欢
    • 2016-04-12
    • 1970-01-01
    • 2017-01-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-15
    • 2017-05-01
    • 1970-01-01
    相关资源
    最近更新 更多