std::shared_ptr
保证是线程安全的。我不知道典型实现使用什么机制来确保这一点,但肯定它必须有一些开销。即使您的应用程序是单线程的,也会出现这种开销。
以上情况如何?如果是这样,这是否意味着它违反了原则:如果您没有使用线程安全保证,那么您不会为不使用的内容付费?#34;
答案 0 :(得分:8)
如果我们查看cppreference的std::shared_ptr页面,则会在实施说明部分中说明以下内容:
为了满足线程安全要求,引用计数器通常使用std::atomic::fetch_add std::memory_order_relaxed递增和递减。
有趣的是要注意实际的实施,例如libstdc++实施文档here说:
对于libstdc ++中的shared_ptr版本,编译器和库 是固定的,这使事情变得更简单:我们有一个原子CAS或 我们没有,请参阅下面的锁定政策了解详情。
选择锁定政策部分说明(强调我的):
有一个_Sp_counted_base类,它是一个模板 在枚举__gnu_cxx :: _ Lock_policy上参数化。整个家庭 类的参数化在锁定策略中,直到 __shared_ptr,__ weak_ptr和__enable_shared_from_this。实际的std :: shared_ptr类使用锁定策略从__shared_ptr继承 参数根据线程模型自动选择 libstdc ++配置的平台,以便最好的 将使用模板专业化。这种设计是必要的,因为 它不符合shared_ptr的额外模板 参数,即使它有一个默认值。可用的政策是:
[...]
3._S_Single
此策略使用不可重入的add_ref_lock()而不进行锁定。在没有--enable-threads的情况下构建libstdc ++时使用它。
并进一步说(强调我的):
对于所有三个策略,引用计数增量和减量为 通过ext / atomicity.h中的函数完成,它检测程序是否正常 是多线程的。 如果只存在一个执行线程 程序然后使用较便宜的非原子操作。
所以至少在这个实现中你不会为你不使用的东西买单。
答案 1 :(得分:4)
至少在i386的boost代码中,boost::shared_ptr
是使用原子CAS操作实现的。这意味着虽然它有一些开销,但它很低。我希望std::shared_ptr
的任何实现都类似。
在高性能数字代码的紧密循环中,我通过切换到原始指针并非常小心地发现了一些加速。但对于普通代码 - 我不担心。