- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
C++11 引入了引用计数智能指针,std::shared_ptr
。由于引用计数,这些指针无法自动回收循环数据结构。然而,引用循环的自动收集被证明是可能的,例如通过 Python 和 PHP 。为了将此技术与垃圾收集区分开来,问题的其余部分将其称为循环中断。
鉴于似乎没有向 C++ 添加等效功能的提议,是否存在一个根本原因,为什么与其他语言中已经部署的循环断路器类似的循环断路器不适用于 std::shared_ptr
?
请注意,这个问题并没有归结为“为什么没有 C++ GC”,即 has been asked before 。 C++ GC 通常是指自动管理所有动态分配对象的系统,通常使用某种形式的 Boehm 保守收集器来实现。 pointed out 认为这样的收集器与 RAII 不匹配。由于垃圾收集器主要管理内存,在内存不足之前甚至可能不会被调用,而 C++ 析构函数管理其他资源,依赖 GC 运行析构函数最多会引入不确定性,最坏的情况是资源匮乏。 bee 还指出,在存在更明确和可预测的智能指针的情况下,完全不需要 GC。
然而,基于库的智能指针循环中断器(类似于引用计数解释器使用的循环中断器)与通用 GC 有重要区别:
shared_ptr
管理的对象。此类对象已经参与共享所有权,因此必须处理延迟的析构函数调用,其确切时间取决于所有权结构。 std::enable_shared_from_this
。不使用它的对象不必为控制块中的额外空间付费来保存循环断路器元数据。 reset()
。这足以打破循环并自动销毁对象。要求对象提供并清除其强引用(根据请求)可确保循环中断器不会破坏封装。 shared_ptr
对象的非确定性破坏。”如果程序员控制循环中断器的调用,它就不会是不确定的。此外,一旦被调用,循环破坏器的行为将是可预测的——它会破坏所有当前已知的循环。这类似于 shared_ptr
析构函数在其引用计数降至零后销毁底层对象的方式,尽管这可能导致“非确定性”级联进一步破坏。 std::vector
可能会运行大量析构函数。 (在 Python 中,循环 gc 是自动运行的,但是在不需要它的代码部分中临时有 API 到 disable it。稍后重新启用 GC 将拾取在此期间创建的所有循环垃圾。)std::weak_ptr
可以轻松避免。”事实上,循环在许多简单的数据结构中很容易出现——例如一棵树, child 有一个指向父的反向指针,或一个双向链表。在某些情况下,复杂系统中异构对象之间的循环只是偶尔以特定模式的数据形成,并且难以预测和避免。在某些情况下,用弱变体替换哪个指针并不明显。 最佳答案
这里有很多问题需要讨论,所以我重写了我的帖子以更好地浓缩这些信息。
自动循环检测
你的想法是有一个 circle_ptr
智能指针(我知道你想把它添加到 shared_ptr
,但谈论一种新类型来比较两者更容易)。这个想法是,如果智能指针绑定(bind)的类型来自某个 cycle_detector_mixin
,这将激活自动循环检测。
这个 mixin 还要求类型实现一个接口(interface)。它必须能够枚举该实例直接拥有的所有 circle_ptr
实例。并且它必须提供使其中之一无效的方法。
我认为这是一个非常不切实际的解决方案。它非常脆弱,需要用户进行大量的手动工作。因此,它不适合包含在标准库中。以下是一些原因。
确定性和成本
"It would introduce non-deterministic destruction of cyclic
shared_ptr
objects." Cycle detection only happens when ashared_ptr
's reference count drops to zero, so the programmer is in control of when it happens. It would therefore not be non-deterministic. Its behavior would be predictable - it would destroy all currently known cycles from that pointer. This is akin to howshared_ptr
destructor destroys the underlying object once its reference count drops to zero, despite the possibility of this causing a "non-deterministic" cascade of further destructions.
shared_ptr
破坏的确定性与您建议的确定性之间存在重大差异。即:
shared_ptr
便宜。
shared_ptr
的析构函数执行原子递减,然后进行条件测试以查看值是否递减为零。如果是,则调用析构函数并释放内存。而已。
circle_ptr
被销毁时,代码都必须遍历数据结构以确定是否存在循环。大多数时候,周期不会存在。但它仍然必须寻找它们,只是为了确定。并且每次销毁
circle_ptr
时都必须这样做。
circle_ptr
的实例无法知道它所属的子对象。它不能自动将指向自身的指针转换为指向其所属类的指针。如果没有这种能力,如果重新分配它,它就无法更新拥有它的
cycle_detector_mixin
中的数据结构。
circle_ptr
需要一组构造函数,这些构造函数被赋予一个指向其拥有实例的指针,该指针派生自
cycle_detector_mixin
。然后,它的
operator=
将能够通知其所有者它已更新。显然,复制/移动分配不会复制/移动拥有实例指针。
circle_ptr
提供一个指向自身的指针。在创建
circle_ptr
实例的每个构造函数和函数中。在它本身和它拥有的任何类中,这些类也不由
cycle_detection_mixin
管理。万无一失。这会在系统中造成一定程度的脆弱性;必须为类型拥有的每个
circle_ptr
实例花费人工。
circle_ptr
包含 3 种指针类型:指向从
operator*
获取的对象的指针、指向实际托管存储的指针以及指向该实例所有者的指针。实例必须包含指向其所有者的指针的原因是它是每个实例的数据,而不是与块本身相关联的信息。是
circle_ptr
的实例需要能够在反弹时告诉其所有者,因此该实例需要该数据。
circle_ptr
实例何时在另一种类型中,何时不在。所以每个
circle_ptr
,即使是那些不使用循环检测功能的,也必须承担这 3 个指针成本。
shared_ptr
(或者更重要的是,用这个功能增加
shared_ptr
)是不可行的。
cycle_detector_mixin
派生的用户来实现获取
circle_ptr
实例列表的方法。相反,您将类注册到
circle_ptr
实例。这允许可以循环的
circle_ptr
实例直接与其拥有的
cycle_detector_mixin
对话。
circle_ptr
对象中的一个无效,从根本上改变了类与其任何
circle_ptr
成员交互的方式。
const int
变量是否 > 0,那么您已经为后面的代码建立了一个不变量,该值是正的。
shared_ptr
,可以围绕此类指针的存在构建不变量。您可以设计您的类,以便指针永远不会为空。因此,没有人必须检查它是否为空。
circle_ptr
不是这种情况。如果您实现了
cycle_detector_mixin
,那么您的代码必须能够处理任何
circle_ptr
实例变为空的情况。因此,您的析构函数不能假设它们是有效的,您的析构函数调用的任何代码也不能做出这种假设。
circle_ptr
指向的对象建立不变量。至少,如果它是
cycle_detector_mixin
及其相关注册等的一部分,则不会。
circle_ptr
实例仍然可以是私有(private)的。但是类(class)愿意放弃对循环检测系统的封装。因此,该类不能再确保某些类型的不变量。
weak_ptr
,用户必须
lock
它。这将返回
shared_ptr
,以确保对象将保持事件状态(如果它仍然存在)。锁定是一个原子操作,就像引用递增/递减一样。所以这都是线程安全的。
circle_ptr
s 可能不是非常线程安全。如果另一个线程释放了对它的最后一个非循环引用,则
circle_ptr
可能会从另一个线程变为无效。
circle_ptr
要求它管理的对象实现
cycle_detector_mixin
,那么你就不可能将这样的指针用于任何其他类型。它不会替代(或扩充)
shared_ptr
。因此,编译器无法帮助检测意外误用。
make_shared_from_this
中获益的唯一方法是尽可能全面地使用它。
cycle_detector_mixin
的用户更有可能遇到多重继承问题。这不是一个小问题。特别是因为
make_shared_from_this
可能会使用
cycle_detector_mixin
来访问派生类,因此您将无法使用虚拟继承。
static_cast
派生。 cycle_detector_mixin
派生类在其自身内部构造一个 cycle_detector_mixin
实例(直接或间接,但不在本身派生自 0x2518122313 到 18 的类中,该类本身派生自 0x2518122313 到 1314 1314 到 1314 到 1314 到 1314 的 18 circle_ptr
子对象都是有效的。由于线程问题,甚至可能在成员函数中变得无效。 cycle_detector_mixin
内的循环检测数据结构。 cycle_ptr
必须大 50%,即使是那些不用于循环检测的。 cycle_ptr
实际上是什么的误解。
"A cycle detector is unnecessary because cycles are not that frequent and they can be easily avoided using
std::weak_ptr
." Cycles in fact turn up easily in many simple data structures - e.g. a tree where children have a back-pointer to the parent, or a doubly-linked list. In some cases, cycles between heterogenous objects in complex systems are formed only occasionally with certain patterns of data and are hard to predict and avoid. In some cases it is far from obvious which pointer to replace with the weak variant.
cycle_detector_mixin
意味着什么。如果类存储
cycle_ptr
,则表示该类拥有该对象的所有权。
shared_ptr
的数组实现给他们的 child ,并有一个指向 parent 的指针。常规指针,而不是智能指针。毕竟,如果树构造正确,则父项将拥有其子项。所以如果一个子节点存在,它的父节点必须存在;如果没有有效的 parent , child 就不能存在。
shared_ptr
,右指针是常规指针。或相反亦然;一种方式并不比另一种方式好。
shared_ptr
来处理问题,让自动系统解决如何处理问题。无论是循环引用还是其他什么,只要让系统解决即可。
unique_ptr
的用途。智能指针的目标不是让您不再考虑所有权;就是你可以直接在代码中表达所有权关系。
unique_ptr
中断循环相比,这些改进有何改进?你现在没有意识到循环何时可能发生并做额外的工作,而是到处做一堆额外的工作。极其脆弱的工作;如果你做错了,你不会比错过一个你应该使用
shared_ptr
的地方更好。只是更糟,因为您可能认为您的代码是安全的。
shared_ptr
。甚至
very first smart pointer paper (PDF) 也从未考虑过这种可能性。扩展
weak_ptr
以通过一些手动工作自动能够处理循环的主题有
never been discussed even on the standard proposal forums 其中
远 已经考虑了更愚蠢的想法。
weak_ptr
和
boost::shared_ptr
部分的等效(这是在创业初期,他们甚至不认为这是可以写一个
shared_ptr
,允许类型转换
shared_ptr
到
weak_ptr
时
shared_ptr
是基础
shared_ptr<T>
)。但即便如此,它也明确表示不会收集周期。它没有花太多时间在为什么不上,但它确实说明了这一点:
However, cycles of collected objects with clean-up functions are problematic. If A and B are reachable from each other, then destroying either one first will violate the ordering guarantee, leaving a dangling pointer. If the collector breaks the cycle arbitrarily, programmers would have no real ordering guarantee, and subtle, time-dependent bugs could result. To date, no one has devised a safe, general solution to this problem [Hayes 92].
关于c++ - `std::shared_ptr`自动循环断路器的可行性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34373460/
我正在计划一个有关主动噪声消除的微 Controller 项目。 想法是: Speaker_1 生成 100-200 Hz 噪声(恒定频率)。 麦克风录制扬声器_1。 信号传递到 DSP 的微 Con
我想在 Android 上开发一个应用程序来测量房间内物体的大小。例如。测量 table 边缘的长度。为此,我将使用来自 imagej 或来自 openCV 的“边缘检测”。然后我会取这条边并定义它的
我们的程序中有一部分可以保存诊断文件,供用户通过电子邮件发送给我们,以便我们帮助他们解决问题。我们可以选择将其保存到桌面,这似乎是当时流行的想法。但是,我有这两个问题: 是否存在我们无法保存到桌面的情
我想制作一个具有音量控制设置选项的应用程序。当任何应用程序开始播放任何声音甚至是电话时,音量将根据我的应用程序的音量而定。我想在 native iOS 平台上制作它。有可能吗?如果可能的话,有什么想法
我有一个主控制器servlet,在其中实例化了一个数据源。 servlet打开和关闭连接。 servlet主要使用“工厂模式”实例化来自应用程序的命令。这是一些代码来解释: public void i
我们能否使用 CGAL 解决以下形式的线性规划可行性问题(如果不能,请提出替代方案): v.x_a > c 和, v.x_b = c 其中v,x_a,x_b,c分别是向量,向量,向量和标量。我想为给定
在我公司的网站上,我们展示了 40 张 100 像素 X 100 像素的图像,代表我们参与的项目。我们有大约 150 个项目,但主页上只显示了 40 个,选择 40 个是随机的。 See Exampl
目前我仍在阅读一些关于 NSTimer 的文档和教程。根据我目前的理解,我们调用计时器并给它一个方法,以便它自己重复。然后我想到了一个主意。(我正在处理其他应用程序项目) 我打算做什么 实现UIWeb
我想构建一个应用程序,用户可以在其中看到他的当前位置,并且所有用户都登录到该应用程序。 我想为 Android 和 IOS 构建它。我可以在 IOS 上使用 Apple Maps 并在 Android
我有一个相当长的业务流程,最终会导致财务运作。 最终重要的是这些最终操作,尽管我必须记录导致它的所有内容。 由于最终操作中包含的所有信息都可以在其他表中获得(在业务过程中使用),因此使用 View 是
我是一名优秀的程序员,十分优秀!