C++ std::enable_shared_from_this() 函数2025年3月22日 | 7 分钟阅读 std::enable_shared_from_this() 函数是 C++ 中的一个实用工具函数,它允许一个对象创建指向自身(它所拥有的对象)的 `std::shared_ptr` 实例。当一个类被 `shared_ptr` 包装时,它可以在类内部安全地获取 `shared_ptr` 引用。 多个 shared_ptr 指向同一对象当一个 std::shared_ptr 管理一个 对象 时,它带有一个引用计数机制。这个引用计数会显示有多少个 `shared_ptr` 对象指向某个特定对象。当引用计数达到零时,在垃圾回收的上下文中,对象会被销毁,这个过程会释放对象所在的内存空间。 现在,假设您有一个已经被 `std::make_shared` 管理的对象(即,对象是通过 `std::make_shared` 创建或传递的)。如果您尝试在对象本身内部通过 `std::enable_shared_from_this` 创建一个新的 `shared_ptr`,使用 `shared_from_this()`,那么当一个 `shared_ptr<T>` 调用 `this` 时,会发生以下情况:
使用 std::enable_shared_from_this 方法std::enable_shared_from_this() 函数旨在解决这个问题,它使得一个已经被 `shared_ptr` 所拥有的对象,能够获取指向自身的另一个 `shared_ptr`,而不会形成新的引用计数。 当对象首次由 `shared_ptr` 管理时(例如,通过 `std::make_shared`),对象会存储指向包含引用计数器的控制块的指针。当您在对象内部使用 `shared_from_this()` 时,它会利用这个已有的控制块,而不是创建一个新的。如果您尝试在对象创建后的第一次 `shared_ptr` 之前使用 `shared_from_this()`,或者当您使用 `shared_ptr 当您使用 `std::enable_shared_from_this` 时,该类存储指向控制块(管理 `shared_ptr` 的引用计数)的弱指针,而不是直接指向对象。当为该对象创建第一个 `shared_ptr` 时,会自动创建此弱指针,所有这些都在后台处理。 使用弱指针的原因是为了避免增加引用计数,同时仍然能够跟踪控制块。这使得对象能够安全地在之后创建指向自己的新的 `shared_ptr` 实例,而不会导致双重引用计数或双重删除等问题。 正如您所知,当调用 `shared_from_this()` 时,它会检查此弱引用。如果弱引用仍然有效(这意味着对象尚未被销毁),它将创建一个新的 `shared_ptr`,该 `shared_ptr` 共享原始 `shared_ptr` 对象指向的对象。新的 `shared_ptr` 不会创建新的引用计数,而是使该对象的引用计数与原始类型 `shared_ptr` 的对象保持一致。 这有助于避免双重删除,只要至少存在一个 `shared_ptr`,对象就保持有效。 示例让我们用一个例子来说明 C++ 中 std::enable_shared_from_this() 函数的用法。 输出 === Testing MyDerived class === MyBase constructor: DerivedObject MyDerived constructor: DerivedObject MyDerived object: DerivedObject, value: 42 derivedPtr use_count(): 2 derivedPtr2 use_count(): 2 Inside manipulateObject() MyDerived object: DerivedObject, value: 42 Another pointer use_count(): 4 After manipulateObject() use_count(): 2 MyDerived destructor: DerivedObject MyBase destructor: DerivedObject === Storing objects in vector === MyBase constructor: BaseObject1 MyBase constructor: DerivedObject1 MyDerived constructor: DerivedObject1 MyBase constructor: DerivedObject2 MyDerived constructor: DerivedObject2 MyBase object: BaseObject1 MyDerived object: DerivedObject1, value: 10 MyDerived object: DerivedObject2, value: 20 === Complex interaction === MyBase constructor: ComplexBaseObject MyBase constructor: ComplexDerivedObject MyDerived constructor: ComplexDerivedObject Inside manipulateObject() MyBase object: ComplexBaseObject Another pointer use_count(): 2 Inside manipulateObject() MyDerived object: ComplexDerivedObject, value: 100 Another pointer use_count(): 3 basePtr use_count(): 1 derivedPtr use_count(): 2 baseFromDerived use_count(): 2 MyDerived destructor: ComplexDerivedObject MyBase destructor: ComplexDerivedObject MyBase destructor: ComplexBaseObject MyBase destructor: BaseObject1 MyDerived destructor: DerivedObject1 MyBase destructor: DerivedObject1 MyDerived destructor: DerivedObject2 MyBase destructor: DerivedObject2 说明该代码演示了在 类 层次结构中使用 `std::enable_shared_from_this()` 函数通过 `std::shared_ptr` 安全地管理对象所有权。基类 `MyBase` 继承自 `std::enable_shared_from_this<MyBase>`,这允许它使用 `shared_from_this()` 创建自身的 `shared_ptr` 实例。派生类 `MyDerived` 扩展了 `MyBase`,并同样利用 `shared_from_this()` 返回转换为其类型的 `shared_ptr` 实例。 `getPtr()` 和 `getDerivedPtr()` 等关键函数可确保对象能够安全地返回 `shared_ptr` 实例,而不会创建单独的引用计数。`manipulateObject()` 函数展示了在回调场景中如何使用 `shared_from_this()` 来维护正确的引用计数。`testDerived()` 函数测试了在派生类中安全使用 `shared_from_this()`,而 `storeObjectsInVector()` 则管理向量中的多个对象。 最后,`complexInteraction()` 函数探讨了基类和派生类之间的多态行为,确保了对象所有权和销毁的正确性。该代码强调了 `shared_from_this()` 如何通过确保所有 `shared_ptr` 实例共享相同的引用计数来防止双重删除等问题,从而保证了安全的对象生命周期管理。 复杂度分析时间复杂度
空间复杂度
|
Thue-Morse 序列,也称为 Prouhet-Thue-Morse 序列,是一种优雅且无限的二进制序列,几十年来一直吸引着数学家、计算机科学家和理论家。它构造简单,结合其丰富的数学性质,使其成为人们极大兴趣和……的主题。
阅读 16 分钟
概述:给定 n 根不同长度的绳子,需要将所有绳子合并成一根。合并任意两根绳子将产生等于两根绳子之和的成本。目标是最小化合并所有绳子的成本....
阅读 4 分钟
算法竞赛中的常见问题大多与“硬币堆”问题有关。本文提供了一种数学观察和高效算法的方法。让我们详细了解如何解决它。问题陈述:您有两个硬币堆 A 和 B,其中 A 和 B...
阅读 4 分钟
Proizvolov恒等式是组合数学中的一个杰出概念,它结合了排列和数字的算术签名。这是一种纯理论上的对峙,尽管经常被用来获得更多关于加法、排列以及两者之间关系的见解。它的恒等式源于...
阅读 8 分钟
简介 本文的主要主题是 C++ 中的 std::exponential_distribution 类,它是标准库中用于生成指数分布随机数的相当有用的工具。当关注泊松过程中事件之间的时间时,这种分布很有应用价值……
阅读 6 分钟
简介 在现代 C++ 编程中使用文件和目录时,可以完成许多操作,包括创建和销毁文件和目录,以及分别读写文件和目录。然而,还有其他至少与这些基本要素一样重要的元素......
11 分钟阅读
简介 C++ 中输入流库的一个重要组成部分是 std::basic_istream::sentry 类,它旨在在执行 I/O 操作之前控制信息流对象的当前条件和能力。Sentry 是一个应用程序类,它确保用户输入操作被执行... ...
阅读 6 分钟
在现代 C++ 中,有效的内存管理对于创建高性能应用程序至关重要。`std::uninitialized_value_construct` 就是这样一个函数,它能够构建未初始化内存中的对象。本文解释了 `std::uninitialized_value_construct`,说明了它的功能,并提供了一些有用的示例来演示如何使用它。C++ 标准库...
5 分钟阅读
在本文中,我们将讨论 C++ 中模板和继承之间的区别。在讨论它们的区别之前,我们必须了解模板和继承及其特性和局限性。什么是模板?模板是函数或类的蓝图或结构。库...
阅读 6 分钟
在本文中,我们将讨论其语法和示例。简介 一个强大的 C++ 工具 std::regex_replace 使程序员能够使用正则表达式查找和替换文本。它是一种搜索字符串中的模式并替换该模式实例的有用方法...
5 分钟阅读
我们请求您订阅我们的新闻通讯以获取最新更新。
我们提供所有技术(如 Java 教程、Android、Java 框架)的教程和面试问题
G-13, 2nd Floor, Sec-3, Noida, UP, 201301, India