什么C ++智能指针实现可用? [英] What C++ Smart Pointer Implementations are available?

查看:148
本文介绍了什么C ++智能指针实现可用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



这是一个从垃圾收集线程其中我想是一个简单的回答生成了很多评论关于一些特定的智能指针实现,所以它似乎值得开始一个新的职位。



最终的问题是什么是C ++中的智能指针的各种实现在那里,比较?



我已经发布了一些我已经使用过的或者至少已经被覆盖的实现,考虑使用作为下面的答案,我的理解他们的差异和相似之处,可能不是100%准确,所以随时检查或根据需要纠正我。



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

解决方案

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 。这是对 std :: shared_ptr 拥有的对象的引用,因此如果 std :: shared_ptr 引用计数降为零。为了访问原始指针,您首先需要通过调用 lock 访问 std :: shared_ptr 如果拥有的指针已经过期并且已经被销毁,它将返回一个空的 std :: shared_ptr 。这是为了避免在使用多个智能指针时无限期挂起引用计数。








boost :: shared_ptr - 可能最容易在最不同的场景(STL,PIMPL,RAII等)中使用,这是一个共享引用计数的智能指针。我听说过在一些情况下对性能和开销的一些投诉,但我必须忽略他们,因为我不记得是什么论据。显然,它是流行足够成为一个待批准的标准C ++对象,没有关于智能指针的规范的任何缺陷。



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



boost :: scoped_ptr - 这是一个简单的智能指针类,很少的开销可能设计为更好的性能替代 boost :: shared_ptr 可用时。它类似于 std :: auto_ptr ,特别是它不能安全地用作STL容器的元素或具有指向同一对象的多个指针。 p>

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 一样,所有必要的数组goodness都被烘焙。这是不可复制的,因此不能在STL容器中使用。我发现几乎任何地方,你发现自己想使用这个你可能只是使用 std :: vector 。我从来没有确定哪个实际上更快或者更少的开销,但这个范围的数组似乎远远少于一个STL矢量。当你想要在堆栈上保持分配时,请考虑 boost :: array






Qt



QPointer - 在Qt 4.0中引入这是一个弱的智能指针,只能使用 QObject 和派生类,在Qt框架中是几乎的一切,所以这不是一个真正的限制。但是有一些限制,即它不提供一个强指针,虽然你可以检查基础对象是否有效与 isNull()你可以找到你的对象在您通过该检查后,特别是在多线程环境中被销毁。 Qt人认为这已经过时了。



QSharedDataPointer - 这是一个强的智能指针,可能与 boost :: intrusive_ptr 有一些内置的线程安全,但它需要你包括引用计数方法( ref deref ),你可以do通过继承 QSharedData 。和很多Qt一样,对象最好通过充分的继承和子类化来使用,一切似乎都是想要的设计。



QExplicitlySharedDataPointer - 非常类似于 QSharedDataPointer 除非它不隐式地调用 detach()。我将这个版本2.0的 QSharedDataPointer 称为在控制方面的微小增加,确切地说,当引用计数降到零后,何时分离不是特别值得一个全新的对象。 QSharedPointer - 原子引用计数,线程安全,共享指针,自定义删除(阵列支持),听起来像一切智能指针应该。这是我主要在Qt中用作智能指针,我发现它可以与 boost:shared_ptr 相当,虽然可能显着更多的开销像许多对象在Qt。



QWeakPointer - 你感觉到一个重复的模式吗?正如 std :: weak_ptr boost :: weak_ptr 这是与 QSharedPointer



qt-project.org/doc/qt-4.8/qscopedpointer.html#details> QScopedPointer - 此名称也应该看起来很熟悉,实际上是基于on boost :: scoped_ptr 与共享和弱指针的Qt版本不同。它的功能是提供一个所有者智能指针,而不需要 QSharedPointer 的开销,这使得它更适合兼容性,异常安全代码和所有你可能使用的东西 std :: auto_ptr boost :: scoped_ptr


Comparisons, Pros, Cons, and When to Use?

This is a spin-off from a garbage collection thread where what I thought was a simple answer generated a lot of comments about some specific smart pointer implementations so it seemed worth starting a new post.

Ultimately the question is what are the various implementations of smart pointers in C++ out there and how do they compare? Just simple pros and cons or exceptions and gotchas to something you might otherwise think should work.

I've posted some implementations that I've used or at least glossed over and considered using as an answer below and my understanding of their differences and similarities which may not be 100% accurate so feel free to fact check or correct me as needed.

The goal is to learn about some new objects and libraries or correct my usage and understanding of existing implementations already widely in use and end up with a decent reference for others.

解决方案

C++03

std::auto_ptr - Perhaps one of the originals it suffered from first draft syndrome only providing limited garbage collection facilities. The first downside being that it calls delete upon destruction making them unacceptable for holding array allocated objects (new[]). It takes ownership of the pointer so two auto pointers shouldn't contain the same object. Assignment will transfer ownership and reset the rvalue auto pointer to a null pointer. Which leads to perhaps the worst drawback; they can't be used within STL containers due to the aforementioned inability to be copied. The final blow to any use case is they are slated to be deprecated in the next standard of C++.

std::auto_ptr_ref - This is not a smart pointer it's actually a design detail used in conjunction with std::auto_ptr to allow copying and assignment in certain situations. Specifically it can be used to convert a non-const std::auto_ptr to an lvalue using the Colvin-Gibbons trick also known as a move constructor to transfer ownership.

On the contrary perhaps std::auto_ptr wasn't really intended to be used as a general purpose smart pointer for automatic garbage collection. Most of my limited understanding and assumptions are based on Herb Sutter's Effective Use of auto_ptr and I do use it regularly although not always in the most optimized way.


C++11

std::unique_ptr - This is our friend who will be replacing std::auto_ptr it will be quite similar except with the key improvements to correct the weaknesses of std::auto_ptr like working with arrays, lvalue protection via private copy constructor, being usable with STL containers and algorithms, etc. Since it's performance overhead and memory footprint are limited this is an ideal candidate for replacing, or perhaps more aptly described as owning, raw pointers. As the "unique" implies there is only one owner of the pointer just like the previous std::auto_ptr.

std::shared_ptr - I believe this is based off TR1 and boost::shared_ptr but improved to include aliasing and pointer arithmetic as well. In short it wraps a reference counted smart pointer around a dynamically allocated object. As the "shared" implies the pointer can be owned by more than one shared pointer when the last reference of the last shared pointer goes out of scope then the object will be deleted appropriately. These are also thread safe and can handle incomplete types in most cases. std::make_shared can be used to efficiently construct a std::shared_ptr with one heap allocation using the default allocator.

std::weak_ptr - Likewise based off TR1 and boost::weak_ptr. This is a reference to an object owned by a std::shared_ptr and will therefore not prevent the deletion of the object if the std::shared_ptr reference count drops to zero. In order to get access to the raw pointer you'll first need to access the std::shared_ptr by calling lock which will return an empty std::shared_ptr if the owned pointer has expired and been destroyed already. This is primarily useful to avoid indefinite hanging reference counts when using multiple smart pointers.


Boost

boost::shared_ptr - Probably the easiest to use in the most varying scenarios (STL, PIMPL, RAII, etc) this is a shared referenced counted smart pointer. I've heard a few complaints about performance and overhead in some situations but I must have ignored them because I can't remember what the argument was. Apparently it was popular enough to become a pending standard C++ object and no drawbacks over the norm regarding smart pointers come to mind.

boost::weak_ptr - Much like previous description of std::weak_ptr, based on this implementation, this allows a non-owning reference to a boost::shared_ptr. You not surprisingly call lock() to access the "strong" shared pointer and must check to make sure it's valid as it could have already been destroyed. Just make sure not to store the shared pointer returned and let it go out of scope as soon as you're done with it otherwise you're right back to the cyclic reference problem where your reference counts will hang and objects will not be destroyed.

boost::scoped_ptr - This is a simple smart pointer class with little overhead probably designed for a better performing alternative to boost::shared_ptr when usable. It's comparable to std::auto_ptr especially in the fact that it can't be safely used as an element of a STL container or with multiple pointers to the same object.

boost::intrusive_ptr - I've never used this but from my understanding it's designed to be used when creating your own smart pointer compatible classes. You need to implement the reference counting yourself, you'll also need to implement a few methods if you want your class to be generic, furthermore you'd have to implement your own thread safety. On the plus side this probably gives you the most custom way of picking and choosing exactly how much or how little "smartness" you want. intrusive_ptr is typically more efficient than shared_ptr since it allows you to have a single heap allocation per object. (thanks Arvid)

boost::shared_array - This is a boost::shared_ptr for arrays. Basically new [], operator[], and of course delete [] are baked in. This can be used in STL containers and as far as I know does everything boost:shared_ptr does although you can't use boost::weak_ptr with these. You could however alternatively use a boost::shared_ptr<std::vector<>> for similar functionality and to regain the ability to use boost::weak_ptr for references.

boost::scoped_array - This is a boost::scoped_ptr for arrays. As with boost::shared_array all the necessary array goodness is baked in. This one is non-copyable and so can't be used in STL containers. I've found almost anywhere you find yourself wanting to use this you probably could just use std::vector. I've never determined which is actually faster or has less overhead but this scoped array seems far less involved than a STL vector. When you want to keep allocation on the stack consider boost::array instead.


Qt

QPointer - Introduced in Qt 4.0 this is a "weak" smart pointer which only works with QObject and derived classes, which in the Qt framework is almost everything so that's not really a limitation. However there are limitations namely that it doesn't supply a "strong" pointer and although you can check if the underlying object is valid with isNull() you could find your object being destroyed right after you pass that check especially in multi-threaded environments. Qt people consider this deprecated I believe.

QSharedDataPointer - This is a "strong" smart pointer potentially comparable to boost::intrusive_ptr although it has some built in thread safety but it does require you to include reference counting methods (ref and deref) which you can do by subclassing QSharedData. As with much of Qt the objects are best used through ample inheritance and subclassing everything seems to be the intended design.

QExplicitlySharedDataPointer - Very similar to QSharedDataPointer except it doesn't implicitly call detach(). I'd call this version 2.0 of QSharedDataPointer as that slight increase in control as to exactly when to detach after the reference count drops to zero isn't particularly worth a whole new object.

QSharedPointer - Atomic reference counting, thread safe, sharable pointer, custom deletes (array support), sounds like everything a smart pointer should be. This is what I primarily use as a smart pointer in Qt and I find it comparable with boost:shared_ptr although probably significantly more overhead like many objects in Qt.

QWeakPointer - Do you sense a reoccurring pattern? Just as std::weak_ptr and boost::weak_ptr this is used in conjunction with QSharedPointer when you need references between two smart pointers that would otherwise cause your objects to never be deleted.

QScopedPointer - This name should also look familiar and actually was in fact based on boost::scoped_ptr unlike the Qt versions of shared and weak pointers. It functions to provide a single owner smart pointer without the overhead of QSharedPointer which makes it more suitable for compatibility, exception safe code, and all the things you might use std::auto_ptr or boost::scoped_ptr for.

这篇关于什么C ++智能指针实现可用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆