虽然通过了解它们是什么很容易了解std::shared_ptr
、std::unique_ptr
和std::weak_ptr
,但我似乎很难理解它们在什么情况下被证明是有用的。
谁能举出其中三个的具体例子?
我假设你知道这些智能指针中的每一个都做了什么,所以我不打算解释它们。相反,我将给你一些例子,说明我如何在我自己的代码中使用它们,或者从我需要它们的库中使用它们。
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<AudioPlayerMixer>
,因此当保存shared_ptr
的最后一个AudioPlayer
实例被销毁时,混音器也将销毁。使用thread_local
只是有助于每个线程具有唯一的AudioPlayerMixer
。AudioPlayerMixer
的thread_local
存储不应延长混频器的寿命,因为AudioPlayerMixer
的寿命取决于AudioPlayer
实例的存在(即没有AudioPlayer
=>没有AudioPlayerMixer
) - 这就是使用weak_ptr
的原因。mixedOutput.expired() == true
意味着此线程上未创建任何AudioPlayer
,或者删除了所有以前存在的玩家。mixedOutput.expired() == false
表示此线程上存在另一个AudioPlayer
,当前AudioPlayer
需要将shared_ptr
到同一混音器。请注意,使用来自多个线程的shared_ptr
和weak_ptr
时必须小心,因为它们不是线程安全的。在此示例中,thread_local
以及仅在同一线程中创建和销毁AudioPlayer
的事实可确保它是安全的。
当然,这一切都可以在没有智能指针的情况下完成,但智能指针有助于更好地传达代码的意图。