另一种类型的智能ptr,比如具有弱refs的unique_ptr
Another type of smart ptr, like unique_ptr with weak refs?
我最近遇到一个问题,unique_ptr
和shared_ptr
似乎都不是正确的解决方案。因此,我正在考虑发明另一种智能ptr(如下所述),但我心想"我肯定不是第一个想要这个的人。">
所以我的高级问题是:
- 下面的设计有意义吗
- 有没有办法用现有的智能ptr(或其他
std::
功能)来实现这一点,也许我错过了什么
要求:
- 我想要单一所有权,很像
unique_ptr
- 也就是说:只有当单个拥有指针死亡时,底层对象才应该被释放(与
shared_ptr
的行为不同)
- 也就是说:只有当单个拥有指针死亡时,底层对象才应该被释放(与
- 我想要一些额外的方法来引用对象,当对象被删除时,它是"可感知的"。所以,类似于
weak_ptr
,但要与单个所有权模型一起使用 - 我不需要线程安全
激励示例:
假设我正在迭代一个接口指针列表,并对它们调用方法。其中一些方法可能会导致列表中稍后的项目被删除。
使用纯指针,我会得到那些已删除项目的悬空引用。
建议设计:
让我们调用拥有指针my_ptr
和非拥有引用my_weak_ptr
。
对于一个给定的对象,我们可能会有这样的图:
_______
my_ptr<Obj> owner ---------> |Obj* | -------> [Obj data ... ]
+----> |count|
| +--> |_____|
my_weak_ptr<Obj> A ---+ |
|
my_weak_ptr<Obj> B -----+
CCD_ 9将具有与CCD_。在内部,它将存储一个指向"控制块"的指针,该指针实际上只是控制块本身的"真实"指针和refcount。在销毁时,my_ptr
会将控制块指针设置为NULL,并递减refcount(并在适当的情况下删除控制块)。
my_weak_ptr
将是可复制的,并且具有一些返回真实Obj*
的get()
方法。用户将负责在使用它之前检查它是否为NULL。在销毁时,my_weak_ptr
将递减计数(并在适当的情况下删除控制块)。
缺点是每次访问都要在内存中跳两次。对于my_ptr
,也可以通过在内部存储真正的Obj*
来减轻这种情况,但my_weak_ptr
引用将始终需要支付双跳成本。
编辑:一些相关问题,来自给定的链接:
- std::unique_ptr的非所有权副本
- 是否可能/希望创建不可复制的共享指针模拟(以启用weak_ptr跟踪/借用类型语义)
- 通过不同类型更好地共享ptr;所有权;以及";引用">
所以似乎有这样的需求,但没有灌篮解决方案。如果需要线程安全,shared_ptr
和weak_ptr
是正确的选择,但如果不需要,它们会增加不必要的开销。
还有boost::local_scoped_ptr
,但它仍然是一种共享所有权模式;我宁愿阻止拥有指针的副本,比如unique_ptr
。
上面的评论中有一些很好的讨论,所以我将尝试回答我自己的问题并总结:
首先,整个概念有一个总体的缺点:my_weak_ptr
的任何用户都需要非常小心,不要调用一些可能导致底层对象被删除的函数。或者,如果他们这样做了,他们需要重新检查弱ptr是否为null。这是对用户施加的一个未强制(以及未强制able)约束,就像他们使用原始指针一样。
话虽如此:这不是一个新领域。在随后的研究中,我发现了这样一个想法的各种化身:
- VISH StrongPtr/WeakPtr
- 非常合身。注意
WeakPtr
没有lock()
方法;如果引用的对象从其他地方被破坏,弱指针就会神奇地变为null"> - 然而,它仍然是可复制的,因此不表示唯一的所有权
- 非常合身。注意
- Loki StrongPtr
- 通过适当使用令人眼花缭乱的策略选择(或者可能是自定义策略),我认为我所描述的可以实现
- 可跟踪_ptr
- 一种不同的方法,因为您的
T
必须封装为trackable<T>
,但类似的问题正在解决
- 一种不同的方法,因为您的
还有一些";相当好但不太理想";更接近std
:的解决方案
- 使用
shared_ptr
和weak_ptr
。- 缺点:线程安全开销、可复制的所有者ptr、多个引用计数
- boost::local_shared_ptr,与
weak_ptr
兼容。- 缺点:可复制的所有者ptr,多个引用计数
local_shared_ptr
可能是最好的开箱即用解决方案,质量高,缺点少。
然而,要想真正挤出最后几个字节,并禁止复制,需要一个自定义的解决方案。
此外,更具哲学意义的是:
从这里的讨论和其他阅读中,我感觉到,许多人相信所有权的二元方法:要么是共享的(所以使用shared_ptr
,它也通过weak_ptr
提供共享观察),要么是唯一的(所以用unique_ptr
)。
这可能涵盖了90%以上的病例。然而,我想要独特的所有权和共同的观察(这是我的措辞;根据你的语义,你可能会使用不同的单词)。标准可能涵盖了太多的角落案例,但我认为对于资源受限的系统来说,这似乎是一个合理的利基市场。
有一种设计不分配额外的块,而是将指针对象大小设置为3个指针。指针是双链表的一个节点,每个弱引用都是同一个链表的节点。
缺点是线性删除的复杂性(必须使每个引用无效),以及使其有效地实现线程安全的不可行性。
优点是快速取消对共享指针和弱指针的引用。
我不记得我到底在哪里见过或听到过这个想法。。。
- CLANG 编译器 说:变量"PTR"可能未初始化
- 在以唯一ptr为值的C++映射中,动态内存何时会被销毁
- 将 ptr 传递给 ptr 到 A 作为参数传递给 A 的函数是不好的做法吗?
- 为共享 ptr 向量实现复制 c'tor?
- 字符和整数中 **(ptr+1) 的值差异
- C++:在不中断共享的情况下通过引用传递共享 PTR?
- 如何将派生类从基 ptr 分配给 nlohmann::json
- 引用 std::shared:ptr 以避免引用计数
- 为什么我不能在不进行任何转换的情况下将浮点数放入任何类型的 ptr 中?
- 在调用函数时,ptr** 和 ptr*& 之间是否有区别,或者首选C++?
- 另一种类型的智能ptr,比如具有弱refs的unique_ptr
- 尝试打印出 *ptr++ 的值,以了解它是如何工作的
- 如何控制共享 ptr 引用计数?
- 如果真的需要std::move,我们应该什么时候声明右值refs
- C++中的指针否定 (!ptr == NULL)
- 从const ptr*转换为ptr*时出现问题
- 这是MSVC 2013中具有共享PTR的单例的正确实现吗?
- 对唯一 ptr 无效读取的引用向量
- C++ 类型转换基础 PTR 到派生 PTR 保存在引用类中
- 如何使用非类型参数传递模板化类的 Ref 或 Ptr