有哪些C++智能指针实现?

AJG*_*G85 121 c++ smart-pointers c++-faq

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

这是从垃圾收集线程中衍生出来的,我认为这是一个简单的答案,它产生了很多关于某些特定智能指针实现的评论,所以看起来值得开始一篇新帖子.

最终问题是C++中智能指针的各种实现是什么,它们如何比较?只是简单的利弊或异常,并找到你可能认为应该工作的东西.

我已经发布了一些我已经使用过或者至少掩饰过的实现,并考虑使用下面的答案,并且我对它们的差异和相似性的理解可能不是100%准确所以请随意根据需要检查或纠正我.

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

AJG*_*G85 229

C++ 03

std::auto_ptr - 也许其初次综合症患者的原件之一仅提供有限的垃圾收集设施.第一个缺点是它要求delete销毁使它们无法接受数组分配的对象(new[]).它需要指针的所有权,因此两个自动指针不应包含相同的对象.赋值将转移所有权并将rvalue自动指针重置为空指针.这可能导致最严重的缺点; 由于上述无法复制,它们不能在STL容器中使用.对任何用例的最后一击是它们将在下一个C++标准中被弃用.

std::auto_ptr_ref- 这不是一个智能指针,它实际上是一个设计细节,用于std::auto_ptr在某些情况下允许复制和分配.具体来说,它可以用于将非const std::auto_ptr转换为左值,使用Colvin-Gibbons技巧(也称为移动构造函数)来转移所有权.

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


C++ 11

std::unique_ptr- 这是我们的朋友将替换std::auto_ptr它将非常相似,除了重要的改进,以纠正std::auto_ptr像数组一样的弱点,通过私有拷贝构造函数的左值保护,可用于STL容器和算法等等.因为它的性能开销并且内存占用有限,这是替换或者更恰当地描述为拥有原始指针的理想候选者.由于"唯一"意味着指针只有一个所有者,就像前一个一样std::auto_ptr.

std::shared_ptr- 我相信这是基于TR1,boost::shared_ptr但改进了包括别名和指针算法.简而言之,它围绕动态分配的对象包装引用计数智能指针.由于"共享"意味着当最后一个共享指针的最后一个引用超出范围时,指针可以由多个共享指针拥有,因此该对象将被适当地删除.这些也是线程安全的,在大多数情况下可以处理不完整的类型.std::make_shared可以用于std::shared_ptr使用默认分配器有效地构造一个堆分配.

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


促进

boost::shared_ptr - 在最不同的场景中可能最容易使用(STL,PIMPL,RAII等),这是一个共享引用的计数智能指针.在某些情况下,我听过一些关于性能和开销的抱怨,但我一定忽略了它们,因为我不记得论证是什么.显然它很受欢迎,成为一个待定的标准C++对象,并且没有关于智能指针的常规的缺点.

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

boost::scoped_ptr- 这是一个简单的智能指针类,其开销很小,可能是为了boost::shared_ptr在可用时提供更好的替代方案.它的可比性std::auto_ptr尤其在于它无法安全地用作STL容器的元素或具有指向同一对象的多个指针.

boost::intrusive_ptr - 我从来没有使用过这个,但根据我的理解,它被设计用于创建自己的智能指针兼容类时.你需要自己实现引用计数,如果你希望你的类是通用的,你还需要实现一些方法,而且你必须实现自己的线程安全.从好的方面来说,这可能会为您提供最自定义的挑选方式,并精确选择您想要多少或多少"聪明".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<>>类似功能并重新获得boost::weak_ptr用于引用的功能.

boost::scoped_array- 这是一个boost::scoped_ptr数组.与boost::shared_array所有必要的阵列良好性相同.这一个是不可复制的,因此不能在STL容器中使用.我发现几乎你发现自己想要使用它的任何地方你可能只是使用它std::vector.我从来没有确定哪个实际上更快或开销更少但这个范围的数组似乎远不如STL向量.当你想在堆栈上保持分配时,请考虑boost::array.


Qt的

QPointer- 在Qt 4.0中引入,这是一个"弱"智能指针,它只适用于QObject派生类,在Qt框架中几乎所有东西都不是真正的限制.但是有一些限制,即它不提供"强"指针,虽然您可以检查底层对象是否有效,但是isNull()您可以在通过该检查后立即销毁对象,尤其是在多线程环境中.Qt人们认为这个被弃用了我相信.

QSharedDataPointer- 这是一个"强大的"智能指针可能具有可比性,boost::intrusive_ptr虽然它有一些内置的线程安全性,但它确实需要你包括引用计数方法(refderef)你可以通过子类化QSharedData.与Qt的大部分内容一样,对象最好通过充足的继承和子类化来使用,所有内容似乎都是预期的设计.

QExplicitlySharedDataPointer- 非常相似,QSharedDataPointer除了它没有隐式调用detach().我将这个版本QSharedDataPointer称为2.0,因为控制稍微增加,以及在引用计数降至零之后准确分离的时间并不特别值得一个全新的对象.

QSharedPointer - 原子引用计数,线程安全,可共享指针,自定义删除(数组支持),听起来像智能指针应该是的一切.这是我在Qt中主要用作智能指针的方法,我发现它可以与boost:shared_ptrQt中的许多对象相比具有更大的开销.

QWeakPointer - 你是否感觉到一种反复出现的模式?正如std::weak_ptrboost::weak_ptr这一起使用,QSharedPointer当你需要两个智能指针,否则将导致您的对象永远不会被删除之间的引用.

QScopedPointer- 这个名称也应该看起来很熟悉,实际上实际上是基于boost::scoped_ptr共享和弱指针的Qt版本.它的作用是提供单个所有者智能指针,而不会产生开销QSharedPointer,使其更适合兼容性,异常安全代码以及您可能使用std::auto_ptrboost::scoped_ptr用于的所有内容.

  • @the_mandrill但是如果拥有类的析构函数是在一个单独的翻译单元(.cpp-file)中定义的,而不是客户端代码,那么无论如何都会在Pimpl-idiom中给出它.因为这个翻译单元通常知道Pimpl的完整定义,因此它的析构函数(当它破坏auto_ptr时)正确地破坏了Pimpl.当我看到这些警告时,我也担心这个,但我尝试了它并且它有效(Pimpl的析构函数被调用).PS.:请使用@ -syntax查看任何回复. (2认同)
  • 通过向文档添加适当的链接,增加了列表的实用性. (2认同)

Gre*_*osz 5

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

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