【问题标题】:What are best use cases of shared_ptr, unique_ptr and weak_ptr?shared_ptr、unique_ptr 和weak_ptr 的最佳用例是什么?
【发布时间】:2021-06-20 09:47:58
【问题描述】:

虽然通过知道它们是什么很容易了解std::shared_ptrstd::unique_ptrstd::weak_ptr,但我似乎很难理解它们在什么情况下被证明是有用的。

谁能给出其中三个的一两个具体例子?

【问题讨论】:

  • 当只有一个东西应该拥有指针时使用unique_ptr。如果您希望多件物品共享所有权,请使用std::shared_ptr。使用weak_ptr 分发一个可以获取指针的存根,如果它还没有被销毁的话。
  • 您所要做的就是想象一个只有 原始指针的世界。 weak_ptr 帮助解决循环引用问题。
  • 在我看来,最好使用std::unique_ptr(连同non-owning原始指针作为函数参数),并避免使用std::shared_ptr。有时std::shared_ptr 确实是最好的解决方案,只有在这种情况下我才会考虑它。与 .NET 平台上的 C# 相比,所有对象都非常像到处都有std::shared_ptrF.27 用于 shared_ptr 原因和示例。
  • 不完全重复,因为该问题仅与共享/弱问题有关,但那里有很多好的答案:stackoverflow.com/q/48834271/126995
  • 阅读Effective Modern C++,答案就在那里。

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


【解决方案1】:

我假设你知道每个智能指针的作用,所以我不打算解释它们。相反,我会举例说明我是如何在自己的代码中或从我使用过的需要它们的库中使用它们的。

std::unique_ptr:可以从 API 返回,表示资源需要由调用者管理,共享对象不安全。例如,gRPC 会像这样创建 CompletionQueue 实例。 CompletionQueue 具有敏感的生命周期和同步要求。通过返回unique_ptr,很明显调用者负责生命周期管理,并且共享CompletionQueue 变得很麻烦。共享它仍然不是不可能的(可以从unique_ptr 获取原始指针或使用对unique_ptr 的引用,这两者都是典型的代码异味)。

std::shared_ptr/std::weak_ptr:不是最简单的用例,但我们开始...

AudioPlayer::AudioPlayer() {
   thread_local std::weak_ptr<AudioPlayerMixer> mixedOutput;

   if (mixedOutput.expired()) {
      m_mixedOutput = std::make_shared<AudioPlayerMixer>();
      mixedOutput = m_mixedOutput;
   } else {
      m_mixedOutput = mixedOutput.lock();
   }
}

在此示例中,线程上的所有AudioPlayer 实例都需要使用AudioPlayerMixer 将它们的音频混合在一起。因此,每个AudioPlayer 都有一个shared_ptr&lt;AudioPlayerMixer&gt;,因此当最后一个持有shared_ptrAudioPlayer 实例被销毁时,混合器也会被销毁。使用thread_local 只是有助于每个线程拥有一个唯一的AudioPlayerMixerthread_localAudioPlayerMixer 存储不应延长混音器的寿命,因为 AudioPlayerMixer 的寿命由 AudioPlayer 实例的存在决定(即没有AudioPlayer => 没有AudioPlayerMixer) - 这就是使用weak_ptr 的原因。 mixedOutput.expired() == true 表示在此线程上没有创建 AudioPlayer 或删除所有以前存在的玩家。 mixedOutput.expired() == false 表示此线程上存在另一个AudioPlayer,当前AudioPlayer 需要将shared_ptr 获取到同一个混音器。请注意,在多个线程中使用shared_ptrweak_ptr 时必须小心,因为它们不是线程安全的。在此示例中,thread_localAudioPlayer 仅在同一线程内创建和销毁这一事实确保了它是安全的。

当然,这一切都可以在没有智能指针的情况下完成,但智能指针有助于更好地传达代码的意图。

【讨论】:

  • 如果目标是从weak_ptr 中获取shared_ptr,通常只使用.lock() 然后检查生成的shared_ptr 是否实际指向某个东西或不是,而是先使用expiredlock()如果过期则返回一个默认构造实例。
  • @FrançoisAndrieux 好点,感谢您的简化。
猜你喜欢
  • 2013-07-06
  • 2016-06-05
  • 2019-11-25
  • 2011-01-03
  • 2011-06-26
  • 2017-05-20
  • 2010-10-03
  • 1970-01-01
  • 2016-08-03
相关资源
最近更新 更多