什么C + +智能指针实现可用?

比较,优点,缺点和何时使用?

这是一个垃圾收集线程的分拆,我认为这是一个简单的答案,产生了一些关于一些特定的智能指针实现的评论,所以似乎值得开始一个新的职位。

最终问题是C ++中的智能指针的各种实现是什么,它们是如何比较的? 只是简单的优点和缺点或exception和陷阱,你可能认为应该工作。

我已经发布了一些我已经使用过的或至less已经被掩盖的实现,并被认为是作为下面的答案,并且我的理解可能不是100%准确的差异和相似之处,所以请随时根据需要进行事实核查或纠正。

目标是了解一些新的对象和库,或者纠正我对已经广泛使用的现有实现的使用和理解,并最终为其他人提供一个体面的参考。

C ++ 03

std::auto_ptr – 也许是从第一次综合症只受到提供有限的垃圾收集设施的原件之一。 第一个缺点是它在调用delete时候会调用delete ,这使得他们不能容纳保存数组的对象( new[] )。 它占用指针的所有权,所以两个自动指针不应该包含同一个对象。 赋值将转移所有权并将右值自动指针重置为空指针。 这可能导致最坏的缺点; 由于上述的无法复制,它们不能在STL容器内使用。 任何用例的最后一击都是在C ++的下一个标准中被弃用。

std::auto_ptr_ref – 这不是一个智能指针,它实际上是一个与std::auto_ptr结合使用的devise细节,允许在某些情况下进行复制和分配。 具体来说,它可以用来转换一个非常量std::auto_ptr左值使用科尔文 – 长臂猿技巧也被称为移动构造函数来转移所有权。

相反,也许std::auto_ptr并不是真正用作自动垃圾收集的通用智能指针。 我的大部分理解和假设都是基于Herb Sutter的“有效使用auto_ptr” ,我经常使用它,尽pipe并不总是以最优化的方式。


C ++ 11

std::unique_ptr – 这是我们的朋友谁将会取代std::auto_ptr它将是非常相似,除了关键的改进,以纠正std::auto_ptr的弱点像工作与数组, 左值保护通过私人拷贝构造,可用使用STL容器和algorithm等等。由于性能开销和内存占用是有限的,因此这是一个理想的替代select,或者可能更适合被描述为拥有原始指针。 由于“唯一”意味着只有一个指针的所有者,就像之前的std::auto_ptr

std::shared_ptr – 我相信这是基于TR1和boost::shared_ptr但改进,以包括别名和指针算术以及。 简而言之,它将引用计数智能指针包装在一个dynamic分配的对象周围。 由于“共享”意味着当最后一个共享指针的最后一个引用超出了作用域时指针可以被多个共享指针所拥有,那么该对象将被适当地删除。 这些也是线程安全的,在大多数情况下可以处理不完整的types。 std::make_shared可以用来有效地构造一个std::shared_ptr ,使用默认分配器进行一次堆分配。

std::weak_ptr – 同样基于TR1和boost::weak_ptr 。 这是对std::shared_ptr拥有的对象的引用,因此如果std::shared_ptr引用计数降到零,将不会阻止对象的删除。 为了访问原始指针,首先需要通过调用lock来访问std::shared_ptr ,如果拥有的指针已经过期并且已经被销毁,它将返回一个空的std::shared_ptr 。 当使用多个智能指针时,这主要用于避免无限制的引用计数。


促进

boost::shared_ptr – 可能是最容易在最不同的情况下使用(STL,PIMPL,RAII等)这是一个共享引用计数的智能指针。 在某些情况下,我听到了一些关于性能和开销的抱怨,但我一定忽略了它们,因为我不记得这个论点是什么。 显然,它已经足够stream行,成为一个待定的标准C ++对象,并且不会出现关于智能指针的标准问题。

boost::weak_ptr – 就像以前对std::weak_ptr描述一样,基于这个实现,这允许非拥有引用boost::shared_ptr 。 您不必惊讶地调用lock()来访问“强”共享指针,并且必须检查以确保它是有效的,因为它可能已经被销毁。 只要确保不要存储返回的共享指针,只要完成它就让它超出范围,否则你就回到循环引用问题,引用计数将挂起,对象不会被销毁。

boost::scoped_ptr – 这是一个简单的智能指针类,可能只有很less的开销,可用于boost::shared_ptr的更好的替代方法。 它可以和std::auto_ptr相媲美,特别是它不能安全地用作STL容器的元素或者指向同一对象的多个指针。

boost::intrusive_ptr – 我从来没有使用过这个,但从我的理解,它被devise为创build自己的智能指针兼容类时使用。 你需要实现自己的引用计数,如果你希望你的类是通用的,你还需要实现一些方法,而且你必须实现自己的线程安全。 从好的一面来看,这可能会给你提供最自定义的方式来挑选和select多less或多less“聪明”你想要的。 intrusive_ptr通常比shared_ptr更高效,因为它允许您为每个对象分配一个堆。 (感谢Arvid)

boost::shared_array – 这是一个boost::shared_ptr数组。 基本上new []operator[] ,当然是delete []被烘烤了。这可以在STL容器中使用,据我所知一切都会boost:shared_ptr虽然不能在这些函数中使用boost::weak_ptr 。 但是,您也可以使用boost::shared_ptr<std::vector<>>来获得类似的function,并重新获得使用boost::weak_ptr作为引用的能力。

boost::scoped_array – 这是一个boost::scoped_ptr数组。 和boost::shared_array所有必要的数组boost::shared_array都被烘焙了。这个是不可复制的,所以不能在STL容器中使用。 我发现几乎任何地方你发现自己想要使用这个,你可能只是使用std::vector 。 我从来没有确定哪个实际上更快或者开销更less,但是这个范围数组似乎比STL向量less得多。 当你想保持在堆栈上的分配考虑boost::array


Qt的

QPointer – 在Qt 4.0中引入的是一个“弱”的智能指针,它只与QObject和派生类一起工作,在Qt框架中它几乎是一切,所以这不是一个限制。 然而有一些限制,即它不提供一个“强”指针,虽然你可以检查底层对象是否与isNull()有效,你可以发现你的对象在你通过这个检查后特别是在multithreading环境中。 Qt人认为我相信这个弃用。

QSharedDataPointer – 这是一个“强”智能指针,可能与boost::intrusive_ptr相媲美,虽然它有一些内置的线程安全性,但它确实需要包含引用计数方法( refderef ),您可以通过子类化QSharedData 。 和Qt中的大部分一样,对象最好通过充分的inheritance和子类来使用,一切似乎都是预期的devise。

QExplicitlySharedDataPointer – 与QSharedDataPointer非常相似,除非不隐式调用detach() 。 我把QSharedDataPointer这个版本2.0称为轻微的增加控制,以至于在引用计数降到零之后何时分离并不是特别值得一个全新的对象。

QSharedPointer – primefaces引用计数,线程安全,可共享指针,自定义删除(数组支持),听起来像一个智能指针应该是一切。 这是我主要用作Qt中的智能指针,我发现它可以与boost:shared_ptr相媲美,尽pipeQt中许多对象可能会有更多的开销。

QWeakPointer – 你感觉到一个重复发生的模式? 就像std::weak_ptrboost::weak_ptr QSharedPointer当你需要两个智能指针之间的引用时,这个函数会和QSharedPointer一起使用,否则会导致你的对象永远不会被删除。

QScopedPointer – 这个名字也应该看起来很熟悉,实际上它基于boost::scoped_ptr不像Qt版本的共享和弱指针。 它的作用是提供一个单一的所有者智能指针,而不需要QSharedPointer的开销,这使得它更适合兼容性,exception安全的代码以及所有可能使用std::auto_ptrboost::scoped_ptr的东西。

还有Loki实现了基于策略的智能指针。

其他有关基于策略的智能指针的参考资料,解决了许多编译器对空基优化以及多重inheritance的支持不足的问题:

  • 智能指针重装上阵
  • 将基于策略的智能指针框架添加到标准库的build议

除了给出的内容之外,还有一些以安全为导向的内容:

SaferCPlusPlus

mse::TRefCountingPointer是一个引用计数智能指针,如std::shared_ptr 。 不同的是, mse::TRefCountingPointer更安全,更小,更快,但没有任何线程安全机制。 它是在“非空”和“固定”(不可重定位)版本,可以安全地假定始终指向有效分配的对象。 所以基本上,如果你的目标对象在asynchronous线程之间共享,那么使用std::shared_ptr ,否则mse::TRefCountingPointer更为优化。

mse::TScopeOwnerPointer类似于boost::scoped_ptr ,但与mse::TScopeFixedPointer一起使用,类似于std::shared_ptrstd::weak_ptr这样的“强 – 弱”指针关系types。

mse::TScopeFixedPointer指向在堆栈上分配的对象,或者在堆栈上分配其“拥有”指针的对象。 (故意地)限制它的function,以提高编译时的安全性,而不会增加运行成本。 “范围”指针的要点本质上是要确定一组简单且足够确定的环境,以至于不需要(运行时)安全机制。

mse::TRegisteredPointer行为就像一个原始指针,只不过它的值在目标对象被销毁时自动设置为null_ptr。 在大多数情况下,它可以用作原始指针的一般replace。 像原始指针一样,它没有任何内在的线程安全性。 但作为交换,在堆栈中分配对象并获得相应的性能优势没有问题。 当运行时检查被启用时,该指针可以安全地访问无效内存。 由于mse::TRegisteredPointer在指向有效对象时与原始指针具有相同的行为,因此可以使用编译时指令“禁用”(自动replace为相应的原始指针),从而可以帮助捕捉错误在debugging/testing/testing版模式下,而在发布模式下不产生间接成本。

这里是描述为什么以及如何使用它们的文章。 (注意,无耻的插件。)