【问题标题】:Shared_ptr and unique_ptr with exceptionShared_ptr 和 unique_ptr 例外
【发布时间】:2016-06-05 18:20:10
【问题描述】:

来自en.cppreference.com

std::unique_ptr 的典型用途包括:

  • 提供异常安全 处理具有动态生命周期的对象的类和函数,通过 保证正常退出和异常退出都删除

  • 将具有动态生命周期的唯一拥有对象的所有权传递给 功能

  • 获取具有动态生命周期的唯一拥有对象的所有权 从函数

  • 作为移动感知容器中的元素类型,例如 std::vector, 它保存指向动态分配对象的指针(例如,如果 需要多态行为)

我对第一点很感兴趣。

在 cppreference.com 中没有提到 shared_ptr。 我找不到在引发异常时不会删除 shared_ptr 的场景。有人可以解释一下是否存在这种可能性吗?

【问题讨论】:

  • @user4581301:但这不是异常相关的问题,对吧?即使没有例外,这也会导致问题?
  • 不,但这是你不能保证删除期限的一个例子。
  • 如果共享对象的分配或构造抛出异常,甚至不会构造共享指针。如果已分配内存,则释放该内存。 (请不要让我用引用标准来证明)

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


【解决方案1】:

让我们看一下std::unique_ptr 如何用于提供异常安全的示例:

someclass *ptr = new someclass;
...
delete ptr; // in case of exception we have problem

所以我们应该使用:

std::unique_ptr<someclass> ptr = std::make_unique<someclass>();
... // no problem

简单、安全且无开销。

那么shared_ptr 可以以同样的方式使用来提供异常安全吗?是的,它可以。但它不应该,因为它是为不同的目的而设计的,并且会产生不必要的开销。所以没有提到它作为这种情况下的工具,但这并不意味着如果它是唯一的所有者,它就不会删除拥有的对象。

【讨论】:

  • 开销发生在哪里?因为 make_shared 可用,对吗?由于所有 shared_ptr 都在堆栈内,所以当堆栈展开时,都必须超出范围,不是吗?
  • @InQusitive 原子(可能阻塞)共享计数器的递增/递减。控制块的内存开销。访问类型擦除的删除器。
  • @InQusitive, shared_ptr 是比unique_ptr 更复杂的对象方式,在它的构造函数和析构函数中具有更多更繁重的操作。例如,shared_ptr 在其析构函数中执行 atomic 递减 - 一个冗长的操作 - 而 unique_ptr 只是调用 deleter。
  • @InQusitive 看来您实际上并不了解shared_ptr 的工作原理。除了shared_ptr 对象(包含一个或两个指针)之外,还有一个控制块(bar 自定义分配器)在堆上分配并由shared_ptr 的所有实例共享给同一对象(并使用别名构造函数创建)。需要实际确定何时可以安全删除对象。该块上的操作使 shared_ptr 在性能方面成本高昂
【解决方案2】:

顾名思义,std::shared_ptr 共享它的指针。如果抛出异常并留下作用域,则共享指针将被销毁,但如果在某处有另一个 std::shared_ptr 是副本,则不会删除底层指针,而只会递减引用计数器。

这就是为什么他们不能保证删除会发生。由于std::unique_ptr唯一的,因此可以提供保证,因为我们知道它是唯一持有指针的人。

【讨论】:

  • 但是每个 shared_ptr 都会超出范围并且会减少 count ,对吧?
  • 由于shared_ptr在栈内,所以当栈展开时,都必须超出范围,不是吗?
  • @InQusitive 是的,它会减少计数。 shared_ptr 在同样的意义上是异常安全的 unique_ptr 是。它只是不打算用于只是提供异常安全性。
  • @InQusitive,shared_ptr 通常被复制多于创建,这就是它的场景。异常安全仅适用于初始创建。
  • @InQusitive 它不一定在堆栈中,它可以在任何地方,就像 C++ 中的任何对象一样。
猜你喜欢
  • 1970-01-01
  • 2021-06-20
  • 2021-08-28
  • 1970-01-01
  • 1970-01-01
  • 2011-10-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多