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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5026197/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 17:12:28  来源:igfitidea点击:

What C++ Smart Pointer Implementations are available?

c++smart-pointersc++-faq

提问by AJG85

Comparisons, Pros, Cons, and When to Use?

比较、优点、缺点以及何时使用?

This is a spin-off from a garbage collection threadwhere 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.

最终的问题是 C++ 中智能指针的各种实现是什么,它们如何比较?只是简单的利弊或例外,以及您可能认为应该工作的一些问题。

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.

我已经发布了一些我已经使用或至少掩盖并考虑用作下面的答案的实现,以及我对它们的差异和相似之处的理解,这些差异和相似之处可能不是 100% 准确,因此请随时根据需要进行事实检查或纠正我。

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.

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

回答by AJG85

C++03

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 deleteupon 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 rvalueauto 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- 也许它遭受初稿综合症的原件之一只提供有限的垃圾收集设施。第一个缺点是它要求delete销毁,使它们不能用于保存数组分配的对象 ( new[])。它获取指针的所有权,因此两个自动指针不应包含相同的对象。赋值将转移所有权并将右值自动指针重置为空指针。这可能导致最糟糕的缺点;由于上述无法复制,它们不能在 STL 容器中使用。对任何用例的最后打击是它们将在下一个 C++ 标准中被弃用。

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

std::auto_ptr_ref- 这不是一个智能指针,它实际上是一个设计细节,用于std::auto_ptr在某些情况下允许复制和分配。具体地说,它可用于一非const转换std::auto_ptr到一个左值使用科尔-长臂猿特技也称为移动构造函数,以转移所有权。

On the contrary perhaps std::auto_ptrwasn'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_ptrand I do use it regularly although not always in the most optimized way.

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



C++11

C++11

std::unique_ptr- This is our friend who will be replacing std::auto_ptrit will be quite similar except with the key improvements to correct the weaknesses of std::auto_ptrlike working with arrays, lvalueprotection 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::unique_ptr- 这是我们的朋友,将要替换std::auto_ptr它会非常相似,除了关键改进以纠正std::auto_ptr诸如使用数组、通过私有复制构造函数进行左值保护、可用于 STL 容器和算法等弱点。因为它是性能开销并且内存占用有限,这是替换原始指针的理想选择,或者更恰当地描述为拥有原始指针。由于“唯一”意味着指针只有一个所有者,就像之前的std::auto_ptr.

std::shared_ptr- I believe this is based off TR1 and boost::shared_ptrbut 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_sharedcan be used to efficiently construct a std::shared_ptrwith one heap allocation using the default allocator.

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

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

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



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::shared_ptr- 可能在最多样化的场景(STL、PIMPL、RAII 等)中最容易使用,这是一个共享引用计数智能指针。在某些情况下,我听到了一些关于性能和开销的抱怨,但我一定忽略了它们,因为我不记得争论是什么。显然,它已经足够流行,成为一个待定的标准 C++ 对象,并且没有想到关于智能指针的规范的缺点。

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::weak_ptr- 与之前对 的描述非常相似std::weak_ptr,基于此实现,这允许对boost::shared_ptr. 您毫不奇怪地调用lock()访问“强”共享指针,并且必须检查以确保它有效,因为它可能已经被销毁。只要确保不要存储返回的共享指针,并在完成后立即让它超出范围,否则您将立即回到循环引用问题,其中引用计数将挂起并且对象不会被销毁。

boost::scoped_ptr- This is a simple smart pointer class with little overhead probably designed for a better performing alternative to boost::shared_ptrwhen usable. It's comparable to std::auto_ptrespecially 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::scoped_ptr- 这是一个简单的智能指针类,开销很小,可能是为了boost::shared_ptr在可用时提供更好的性能替代品而设计的。它的可比性std::auto_ptr尤其在于它不能安全地用作 STL 容器的元素或具有指向同一对象的多个指针。

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_ptris typically more efficient than shared_ptrsince it allows you to have a single heap allocation per object. (thanks Arvid)

boost::intrusive_ptr- 我从未使用过它,但据我所知,它旨在在创建您自己的智能指针兼容类时使用。你需要自己实现引用计数,如果你希望你的类是通用的,你还需要实现一些方法,此外你必须实现自己的线程安全。从好的方面来说,这可能为您提供了最自定义的方式来挑选和选择您想要多少或多少“智能”。intrusive_ptr通常比shared_ptr它更有效,因为它允许您为每个对象分配一个堆。(感谢阿维德)

boost::shared_array- This is a boost::shared_ptrfor 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_ptrdoes although you can't use boost::weak_ptrwith these. You could however alternatively use a boost::shared_ptr<std::vector<>>for similar functionality and to regain the ability to use boost::weak_ptrfor references.

boost::shared_array- 这是一个boost::shared_ptr数组。基本上new []operator[],当然,delete []都被烘烤了。这可以在 STL 容器中使用,据我所知boost:shared_ptr,尽管你不能使用boost::weak_ptr这些容器,但它可以做任何事情。但是,您也可以将 aboost::shared_ptr<std::vector<>>用于类似功能并重新获得boost::weak_ptr用于引用的能力。

boost::scoped_array- This is a boost::scoped_ptrfor arrays. As with boost::shared_arrayall 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::arrayinstead.

boost::scoped_array- 这是一个boost::scoped_ptr数组。与boost::shared_array所有必要的数组优点一样,这个数组是不可复制的,因此不能在 STL 容器中使用。我发现几乎在任何您想要使用它的地方,您可能都可以使用std::vector. 我从来没有确定哪个实际上更快或开销更少,但是这个范围数组似乎比 STL 向量少得多。当您想在堆栈上保留分配时,请考虑boost::array



Qt

Qt

QPointer- Introduced in Qt 4.0 this is a "weak" smart pointer which only works with QObjectand derived classes, which in the Qt framework is almosteverything 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.

QPointer- 在 Qt 4.0 中引入这是一个“弱”智能指针,它只适用于QObject派生类,在 Qt 框架中它几乎是一切,所以这并不是真正的限制。但是有一些限制,即它不提供“强”指针,尽管您可以检查基础对象是否有效,isNull()但在通过该检查后会发现您的对象立即被销毁,尤其是在多线程环境中。我相信 Qt 人们认为这已被弃用。

QSharedDataPointer- This is a "strong" smart pointer potentially comparable to boost::intrusive_ptralthough it has some built in thread safety but it does require you to include reference counting methods (refand 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.

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

QExplicitlySharedDataPointer- Very similar to QSharedDataPointerexcept it doesn't implicitly call detach(). I'd call this version 2.0 of QSharedDataPointeras 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.

QExplicitlySharedDataPointer- 非常相似,QSharedDataPointer除了它没有隐式调用detach(). 我将这个版本QSharedDataPointer称为2.0 版本,因为在引用计数下降到零后对何时分离的控制略有增加并不是特别值得一个全新的对象。

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_ptralthough probably significantly more overhead like many objects in Qt.

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

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

QWeakPointer- 您是否感觉到重复出现的模式?正如std::weak_ptrand boost::weak_ptrthis 与QSharedPointer当您需要两个智能指针之间的引用时结合使用,否则将导致您的对象永远不会被删除。

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

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

回答by Gregory Pakosz

There is also Lokiwhich implements policy-based smart pointers.

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

Other references on policy-based smart pointers, addressing the problem of the poor support of the empty base optimization along with multiple inheritance by many compilers:

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

回答by Noah

In addition to the ones given, there are some safety oriented ones too:

除了给出的那些,还有一些安全导向的:

SaferCPlusPlus

SaferCPlusPlus

mse::TRefCountingPointeris a reference counting smart pointer like std::shared_ptr. The difference being that mse::TRefCountingPointeris safer, smaller and faster, but does not have any thread safety mechanism. And it comes in "not null" and "fixed" (non-retargetable) versions that can be safely assumed to always be pointing to a validly allocated object. So basically, if your target object is shared among asynchronous threads then use std::shared_ptr, otherwise mse::TRefCountingPointeris more optimal.

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

mse::TScopeOwnerPointeris similar to boost::scoped_ptr, but works in conjunction with mse::TScopeFixedPointerin a "strong-weak" pointer relationship kind of like std::shared_ptrand std::weak_ptr.

mse::TScopeOwnerPointer类似于boost::scoped_ptr,但在mse::TScopeFixedPointer“强弱”指针关系中与std::shared_ptr和 结合使用std::weak_ptr

mse::TScopeFixedPointerpoints to objects that are allocated on the stack, or whose "owning" pointer is allocated on the stack. It is (intentionally) limited in it's functionality to enhance compile-time safety with no runtime cost. The point of "scope" pointers is essentially to identify a set of circumstances that are simple and deterministic enough that no (runtime) safety mechanisms are necessary.

mse::TScopeFixedPointer指向在堆栈上分配的对象,或者其“拥有”指针在堆栈上分配的对象。它(有意)限制了它在没有运行时成本的情况下增强编译时安全性的功能。“范围”指针的要点本质上是识别一组足够简单和确定性的环境,不需要(运行时)安全机制。

mse::TRegisteredPointerbehaves like a raw pointer, except that its value is automatically set to null_ptr when the target object is destroyed. It can be used as a general replacement for raw pointers in most situations. Like a raw pointer, it does not have any intrinsic thread safety. But in exchange it has no problem targeting objects allocated on the stack (and obtaining the corresponding performance benefit). When run-time checks are enabled, this pointer is safe from accessing invalid memory. Because mse::TRegisteredPointerhas the same behavior as a raw pointer when pointing to valid objects, it can be "disabled" (automatically replaced with the corresponding raw pointer) with a compile-time directive, allowing it to be used to help catch bugs in debug/test/beta modes while incurring no overhead cost in release mode.

mse::TRegisteredPointer行为类似于原始指针,不同之处在于它的值在目标对象被销毁时自动设置为 null_ptr。在大多数情况下,它可以用作原始指针的一般替代品。像原始指针一样,它没有任何内在的线程安全性。但是作为交换,它针对堆栈上分配的对象(并获得相应的性能优势)没有问题。启用运行时检查时,此指针不会访问无效内存。由于mse::TRegisteredPointer在指向有效对象时具有与原始指针相同的行为,因此可以使用编译时指令“禁用”(自动替换为相应的原始指针),从而允许使用它来帮助捕获调试/测试中的错误/beta 模式,而在发布模式下不会产生开销成本。

Hereis an article describing why and how to use them. (Note, shameless plug.)

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