问题描述
我有点习惯了通过COM引用计数的概念,我对shared_ptr有点新。有几个不错的属性与CComPtr,我在shared_ptr中找不到,我想知道是什么模式,防止miss_ptr。
-
AddRef / Release模式保证每个对象只有一个引用计数(引用计数存储在对象本身),因此当你有一个随机指针创建一个CComPtr时,它是安全的。另一方面,shared_ptr有一个单独的refcount指针,因此在对象上创建一个新的shared_ptr是不安全的(为什么标准提供了一个构造函数,如果shared_ptr这么不安全呢?)。这似乎是一个很大的限制,我不明白如何使用shared_ptrs ...
-
有点儿的情况:过去的AddRef / Release:我想要一个弱引用到IFoos的容器(例如从URL到IConnection或某物的地图)。使用weak_ptr,我可以做到,但我的集合不会清理自己,我会有过期的指针。使用Release,我可以实现我自己的弱指针(一点工作),实际上清理集合。有共享/ weak_ptr吗?
- 直观地,在执行两个内存分配创建一个对象(一个用于引用计数,为对象)相比,IUnknown世界,你只做一个。当访问对象时,还存在局部性惩罚(假设AddRef之后经常读取对象的内容,这似乎很可能)。是否比较了这两种方法的成本?
只有 shared_ptr
没有侵入的方式。您可以在任何上使用 shared_ptr
。我甚至使用它们从C接口的对象,通过使用析构函数。例如 cairo_t *
等等。
你不能用 CComPtr
来做到这一点。它只适用于 IUnknown
样式对象。
此外,还有 std :: make_shared
,它直接从对象类型和构造函数的参数创建一个 shared_ptr
。所以你永远不会看到指针(它通常分配对象和其ref-count在一个分配,而不是两个)。
适当的C ++成语与 shared_ptr
很简单:总是使用 make_shared
或 alloc_shared
。如果不能使用它们,那么正确的用法是仅使用直接裸指针构造函数与 new
: shared_ptr< T> pVal {new T {...}};
不要在不知道其起源的指针上使用它。
不,但有工具, 。除了明显的方法(定期运行你的收集并删除死 weak_ptr
s),你可以关联一个删除器与 shared_ptr
这将(除了删除指针)调用任何清理函数,以删除 weak_ptr
。
请参阅<$ c $
您不必复制 shared_ptr
来跟它的内容交谈,你也不必碰撞引用计数这样做。
现在,让我们来谈谈一些 CComPtr
不能。它是侵入性的。它不能与任意分配器或删除器一起使用(当它是侵入时显然不重要)。它不能做指针别名,其中你有一个 shared_ptr
给一个对象的成员,但实际引用计数是为它的成员的对象。这是一个非常有用的事情,能够做。
哦,是。它不绑定到COM, IUnknown
,以及所有 开销。
I'm somewhat used to the concept of refcounting through COM and I'm somewhat new to shared_ptr. There are several nice properties with CComPtr that I don't find in shared_ptr, and I'm wondering what are the pattern that prevent missuse of shared_ptr.
The AddRef/Release pattern guarantees there is only one refcount per object (the refcount is stored on the object itself), so it's safe, when you have a random pointer to create a CComPtr around it. On the other hand, shared_ptr has a separate refcount pointer, so it's unsafe to create a new shared_ptr on an object (why does the standard provide a constructor that takes a T* on shared_ptr if it's so unsafe to do?). That seems such a big limitation that I don't understand how one can use shared_ptrs...
A bit corner case: something that I've done in the past with AddRef/Release: I want a container of "weak references" to IFoos (for example a map from URL to IConnection or something). With weak_ptr, I can do that but my collection won't "clean itself up", I'll have expired pointers in it. With Release, I can implement my own weak pointer (a bit of work) that actually cleans up the collection. Is there an alternative with shared/weak_ptr?
Intuitively, there is a performance penalty in doing two memory allocations to create an object (one for the refcount, one for the object) compared to the IUnknown world where you do only one. There is also a locality penalty when accessing the object (assuming that an AddRef is frequently followed by reading the content of the object, which seems likely). Has the cost of both approaches been compared?
Because it's the only way to have shared_ptr
s without being intrusive. You can use a shared_ptr
on anything. I've even used them on objects from C interfaces, via the use of a destructor. Things like a cairo_t*
and so forth. That way, I never have to free anything ever again.
You can't do that with CComPtr
; it only works for IUnknown
-style objects.
Also, there is std::make_shared
, which creates a shared_ptr
directly from an object types and the argument to the constructor. So you never even see the pointer (and it usually allocates the object and its ref-count in one allocation instead of two).
The proper C++ idiom with shared_ptr
is very simple: always use make_shared
or alloc_shared
. If you can't use them, then the proper idiom is to only use the direct naked pointer constructor in tandem with new
: shared_ptr<T> pVal{new T{...}};
Never use it on pointers that you don't know the origin of.
No, but there are tools to make one if you so desire. Besides the obvious method (run through your collection periodically and remove dead weak_ptr
s), you can associate a deleter with the shared_ptr
that will (in addition to deleting the pointer) call whatever cleanup function to remove those weak_ptr
s.
See make_shared
, above.
You don't have to copy the shared_ptr
to talk to its contents, nor do you have to bump the reference count to do so.
Now, let's talk about some of the things CComPtr
can't do. It's intrusive. It can't be used with arbitrary allocators or deleters (obviously not as important when it's intrusive). It can't do pointer aliasing, where you have a shared_ptr
to a member of an object, but the actual reference count is for the object it is a member of. That's a very useful thing to be able to do.
Oh yeah, it's not cross-platform. It's not bound to COM, IUnknown
, and all of that overhead.
这篇关于shared_ptr对CComPtr的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!