我有点习惯通过COM引用引用计数的概念,而且我对shared_ptr有些新意。 CComPtr有几个不错的属性,我在shared_ptr中找不到,我想知道什么是防止错误使用shared_ptr的模式。
AddRef / Release模式保证每个对象只有一个refcount(refcount存储在对象本身上),所以当你有一个随机指针在它周围创建一个CComPtr时它是安全的。另一方面,shared_ptr有一个单独的refcount指针,因此在一个对象上创建一个新的shared_ptr是不安全的(为什么标准提供了一个构造函数,如果它不安全那么在shared_ptr上取一个T *)。这似乎是一个很大的限制,我不明白如何使用shared_ptrs ......
一个小角落的案例:我过去用AddRef / Release做过的事情:我想要一个对IFoos有“弱引用”的容器(例如从URL到IConnection的地图或其他东西)。使用weak_ptr,我可以做到这一点,但我的收藏不会“清理自己”,我会在其中过期指针。使用Release,我可以实现我自己的弱指针(一些工作),它实际上清理了集合。是否有使用shared / weak_ptr的替代方法?
直观地说,在执行两次内存分配以创建对象(一个用于引用计数,一个用于对象)与IUnknown世界(仅执行一个对象)相比,存在性能损失。访问对象时也存在局部性损失(假设经常跟随AddRef读取对象的内容,这似乎很可能)。这两种方法的成本是否已经进行了比较?
答案 0 :(得分:4)
为什么标准提供了一个构造函数,如果它不安全的话,它会在shared_ptr上获取T *?
因为这是shared_ptr
没有侵入性的唯一方法。您可以在任何上使用shared_ptr
。我甚至通过使用删除对象在C接口的对象上使用它们。像cairo_t*
等等。这样,我再也不用任何东西了。
CComPtr
你无法做到这一点;它只适用于IUnknown
- 样式的对象。
此外,还有std::make_shared
,它直接从对象类型和构造函数的参数创建shared_ptr
。所以你甚至从来没有看到指针(它通常在一个分配而不是两个分配中分配对象及其引用计数。)
使用shared_ptr
的正确C ++习语非常简单:始终使用make_shared
或alloc_shared
。如果无法使用它们,那么正确的习惯用法是仅使用直接裸指针构造函数与new
:shared_ptr<T> pVal{new T{...}};
一起使用(或者创建指针的适当函数。切勿在不知道原点的指针上使用它。
是否有使用shared / weak_ptr的替代方法?
不,但如果您愿意,还有工具可以制作一个。除了显而易见的方法(定期运行您的集合并删除死weak_ptr
),您可以将删除器与shared_ptr
相关联(除了删除指针之外)调用任何清理函数来删除那些weak_ptr
秒。
直观地说,在进行两次内存分配以创建对象时存在性能损失
请参阅上面的make_shared
。
访问对象时也存在局部性损失(假设经常跟随AddRef读取对象的内容,这似乎很可能)。
您无需复制shared_ptr
即可与其内容进行对话,也无需违反引用计数。
现在,我们来谈谈CComPtr
无法做的一些事情。这是侵入性的。它不能与任意分配器或删除器一起使用(当它是侵入时显然不那么重要)。它不能执行指针别名,对象的成员有shared_ptr
,但实际的引用计数是它所属的对象。这是一件非常有用的事情。
哦,是的,不是跨平台的。它不受COM,IUnknown
以及所有 开销的限制。