enable_shared_from_this使用介绍

文章目录

    • enable_shared_from_this定义
    • 使用场合
    • 源码实现
    • 注意

enable_shared_from_this定义

定义于头文件

template< class T > class enable_shared_from_this;  (C++11) 

std::enable_shared_from_this 能让其一个对象(假设其名为 t ,且已被一个 std::shared_ptr 对象 pt 管理)安全地生成其他额外的 std::shared_ptr 实例(假设名为 pt1, pt2, … ) ,它们与 pt 共享对象 t 的所有权。

若一个类 T 继承 std::enable_shared_from_this ,则会为该类 T 提供成员函数: shared_from_this。当 T 类型对象 t 被一个为名为 pt 的 std::shared_ptr 类对象管理时,调用 T::shared_from_this 成员函数,将会返回一个新的 std::shared_ptr 对象,它与 pt 共享 t 的所有权。

使用场合

  • 需要在类对象的内部中获得一个指向当前对象的 shared_ptr 对象。
  • 通过类的成员函数安全的获取对象的this指针,一般来说我们不建议直接返回this指针,可以想象下有这么一种情况,返回的this指针保存在外部一个局部/全局变量,当对象已经被析构了,但是外部变量并不知道指针指向的对象已经被析构了,如果此时外部使用了这个指针就会发生程序奔溃。

崩溃示例:

#include <iostream>
#include <memory>class Foo{
public:Foo(){std::cout << "Foo::Foo constructor run" << std::endl;}~Foo(){std::cout << "Foo::~Foo destructor run" << std::endl;}std::shared_ptr<Foo> GetSharedObject(){return std::shared_ptr<Foo>(this);}
};int main()
{std::shared_ptr<Foo> p(new Foo());std::shared_ptr<Foo> q = p->GetSharedObject();std::cout << p.use_count() << std::endl;std::cout << q.use_count() << std::endl;return 0;
}

程序运行输出:

Foo::Foo constructor run
1
1
Foo::~Foo destructor run
Foo::~Foo destructor run

从程序运行输出看出,析构函数调用了2次,这明显跟我们的预期不符。

借助指针指针可以很轻松的解决这个问题:

#include <iostream>
#include <memory>class Foo : public std::enable_shared_from_this<Foo>
{
public:Foo(){std::cout << "Foo::Foo constructor run" << std::endl;}~Foo(){std::cout << "Foo::~Foo destructor run" << std::endl;}std::shared_ptr<Foo> GetSharedObject(){return shared_from_this();}
};int main()
{std::shared_ptr<Foo> p(new Foo());std::shared_ptr<Foo> q = p->GetSharedObject();std::cout << p.use_count() << std::endl;std::cout << q.use_count() << std::endl;return 0;
}

程序运行输出:

Foo::Foo constructor run
2
2
Foo::~Foo destructor run

源码实现

template<typename _Tp>
class enable_shared_from_this
{
protected:enable_shared_from_this() { }enable_shared_from_this(const enable_shared_from_this&) { }enable_shared_from_this&operator=(const enable_shared_from_this&){ return *this; }~enable_shared_from_this() { }public:shared_ptr<_Tp>shared_from_this(){ return shared_ptr<_Tp>(this->_M_weak_this); }shared_ptr<const _Tp>shared_from_this() const{ return shared_ptr<const _Tp>(this->_M_weak_this); }private:/***@brief _M_weak_assign函数在类型T被包覆在shared_ptr的过程中会被调用*/template<typename _Tp1>void_M_weak_assign(_Tp1* __p, const __shared_count<>& __n) const{ _M_weak_this._M_assign(__p, __n); }template<typename _Tp1>friend void__enable_shared_from_this_helper(const __shared_count<>& __pn,const enable_shared_from_this* __pe,const _Tp1* __px){if (__pe != 0)__pe->_M_weak_assign(const_cast<_Tp1*>(__px), __pn);
}mutable weak_ptr<_Tp>  _M_weak_this; // const函数也可以修改该变量
};/***@brief 共享智能指针*/
template<typename _Tp>
class shared_ptr
: public __shared_ptr<_Tp>
{
public:shared_ptr(): __shared_ptr<_Tp>() { }// ...
};template<typename _Tp, _Lock_policy _Lp>
class __shared_ptr
{
public:typedef _Tp   element_type;__shared_ptr(): _M_ptr(0), _M_refcount() // never throws{ }// 智能指针构造会调用__enable_shared_from_this_helpertemplate<typename _Tp1>explicit__shared_ptr(_Tp1* __p)
: _M_ptr(__p), _M_refcount(__p){__glibcxx_function_requires(_ConvertibleConcept<_Tp1*, _Tp*>)typedef int _IsComplete[sizeof(_Tp1)];__enable_shared_from_this_helper(_M_refcount, __p, __p);
}//...
};

注意

enable_shared_from_this 其内部保存着一个对 this 的弱引用(例如 std::weak_ptr )。 std::shared_ptr 的构造函数检测无歧义且可访问的 (C++17 起) enable_shared_from_this 基类,并且若内部存储的弱引用未为生存的 std::shared_ptr 占有,则 (C++17 起)赋值新建的 std::shared_ptr 为内部存储的弱引用。为已为另一 std::shared_ptr 所管理的对象构造一个 std::shared_ptr ,将不会考虑内部存储的弱引用,从而将导致未定义行为。

只允许在先前已被std::shared_ptr 管理的对象上调用 shared_from_this 。否则调用行为未定义 (C++17 前)抛出 std::bad_weak_ptr 异常(通过 shared_ptr 从默认构造的 weak_this 的构造函数) (C++17 起)。

enable_shared_from_this 提供安全的替用方案,以替代 std::shared_ptr(this) 这样的表达式(这种不安全的表达式可能会导致 this 被多个互不知晓的所有者析构)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/195549.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

iOS17苹果备忘录怎么设置提醒?

在我们快节奏的生活中&#xff0c;苹果备忘录成了记录灵感、任务和重要事项的得力助手&#xff0c;面对着一个让人头疼的问题——备忘录竟然不能设置提醒&#xff01;突然感觉我的备忘录只是个寂寞的清单&#xff0c;没有提醒的陪伴。 于是&#xff0c;我着手寻找解决之道&…

数组逆序重放

数组逆序重放的意思是将数组的元素逆序排列&#xff0c;然后重新放回原数组中。这个操作可以在很多编程语言中实现&#xff0c;例如Python、Java等。 下面是一个Python的示例代码&#xff0c;可以实现这个操作&#xff1a; def reverse_and_rearrange(arr): # 反转数组 …

二维码智慧门牌管理系统升级解决方案:重新制牌审核快速审批

文章目录 前言一、快速审批与重新安装一、其他系统优势 前言 随着城市化进程的加速&#xff0c;门牌号码的管理变得日益重要。然而&#xff0c;传统的门牌管理方式已经无法满足现代社会的需求。在这样的背景下&#xff0c;二维码智慧门牌管理系统应运而生。但随着系统使用&…

LLM之RAG实战(一):使用Mistral-7b, LangChain, ChromaDB搭建自己的WEB聊天界面

一、RAG介绍 如何使用没有被LLM训练过的数据来提高LLM性能&#xff1f;检索增强生成&#xff08;RAG&#xff09;是未来的发展方向&#xff0c;下面将解释一下它的含义和实际工作原理。 ​ 假设您有自己的数据集&#xff0c;例如来自公司的文本文档。如何让ChatGPT和其他…

Golang使用Swagger文档教程

Golang开发效率是杠杠滴&#xff0c;简单几行代码就可完成一个可用的服务&#xff0c;如下代码&#xff1a; 采用Gin作为web framework采用Gorm作为持久化ORM采用Swagger作为OpenAPI文档管理工具 package mainimport ("encoding/csv""fmt""os"…

MQTT的会话及练习

服务端的会话状态 1. 客户端订阅的消息 2. 已发送&#xff0c;但还未完成确认的QoS 1和QoS 2消息 3. 等待发送的QoS 0,QoS 1,QoS 2消息 4. 从客户端收到的&#xff0c;还没有完成确认的QoS 2消息 5. 遗嘱消息和遗嘱延迟间隔 6. 会话是否存在客户端的会话状态 1. 已发送但未完…

LeetCode [中等]岛屿数量

200. 岛屿数量 - 力扣&#xff08;LeetCode&#xff09; 找到值为1的节点之后递归调用DFS遍历&#xff0c;并使用与地图数据结构相同的二维数组visited来保存该点是否访问过 深度优先遍历 public class Solution {static int[][] dirs {new int[]{-1, 0}, new int[]{1, 0},…

【Linux | 编程实践】防火墙 (网络无法访问)解决方案 Vim常用快捷键命令

&#x1f935;‍♂️ 个人主页: AI_magician &#x1f4e1;主页地址&#xff1a; 作者简介&#xff1a;CSDN内容合伙人&#xff0c;全栈领域优质创作者。 &#x1f468;‍&#x1f4bb;景愿&#xff1a;旨在于能和更多的热爱计算机的伙伴一起成长&#xff01;&#xff01;&…

android开发的app选择图片后闪退

在Android开发过程中&#xff0c;可能会遇到选择图片后应用程序崩溃的情况。这种情况可能会使开发者非常困惑并且浪费很多时间。但是&#xff0c;如果你了解这种崩溃的原因&#xff0c;你就可以快速的解决它。本文将详细介绍为什么会出现选择图片后应用程序崩溃的情况。 在And…

LeetCode | 226. 翻转二叉树

LeetCode | 226. 翻转二叉树 OJ链接 不为空就翻转&#xff0c;空空就停止翻转左子树的节点给了右子树右子树的节点给了左就完成了翻转 struct TreeNode* invertTree(struct TreeNode* root) {//不为空就进行翻转if(root){//翻转struct TreeNode* tmp root->left;root->…

计算机网络安全问题分析与防护措施研究

计算机网络安全问题分析与防护措施研究 【摘要】在信息技术快速发展的今天&#xff0c;网络对于人类的生活方式影响显著增强&#xff0c;网络技术快速地在社会各个领域普及&#xff0c;使得计算机网络的安全成为一个亟待解决的问题。如何能够保证网络的快速健康发展己成为研究…

数据库之 redis

前言&#xff1a; 就学习爬虫而言&#xff0c;对于三种常见的数据库做个基本了解足以&#xff0c;所以笔记都是浅尝辄止&#xff0c;不会涉及太深入的东西。 redis简介 Redis&#xff08;Remote Dictionary Server &#xff0c;远程字典服务&#xff09; 是一个使用ANSI C编写…

❀My学习Linux命令小记录(12)❀

目录 ❀My学习Linux命令小记录&#xff08;12&#xff09;❀ 46.arp指令 47.tcpdump指令 48.chmod指令 49.chown指令 50.bash调用脚本指令 shell介绍 shell脚本的组成部分 脚本执行方式 检查脚本语法 bash之变量 变量的种类&#xff1a;根据生效的范围不同来区分 …

GO基础之基本数据类型

基本数据类型 整型 整型分为以下两个大类&#xff1a; 按长度分为&#xff1a;int8、int16、int32、int64 对应的无符号整型&#xff1a;uint8、uint16、uint32、uint64 其中&#xff0c;uint8就是我们熟知的byte型&#xff0c;int16对应C语言中的short型&#xff0c;int64对应…

简单可行的SeruatV4的安装方案

目前Seurat的版本从V4升级到了V5&#xff0c;由于一些变化&#xff0c;导致当年取巧&#xff0c;使用获取数据的方法都无法在V5中使用。 建议在操作前重启下Rstudio&#xff08;或更确切的说是R&#xff09;&#xff01;&#xff01;&#xff01; 那么如何确保自己能够安装V4的…

活动回顾|德州仪器嵌入式技术创新发展研讨会(上海站)成功举办,信驰达科技携手TI推动技术创新

2023年11月28日&#xff0c;德州仪器(TI)嵌入式技术创新发展研讨会在上海顺利举办。作为TI中国第三方IDH&#xff0c;深圳市信驰达科技有限公司受邀参加&#xff0c;并设置展位&#xff0c;展出CC2340系列低功耗蓝牙模块及TPMS、蓝牙数字钥匙解决方案&#xff0c;与众多业内伙伴…

Vue框架学习笔记——列表渲染:v-for

文章目录 前文提要代码正文 前文提要 本人仅做个人学习记录&#xff0c;如有错误&#xff0c;请多包涵 主要学习链接&#xff1a;尚硅谷Vue2.0Vue3.0全套教程丨vuejs从入门到精通 代码正文 <body><div id"box"><ul><li v-for"(p,index)…

Synchronized关键字的底层原理

Synchronized实现 Synchronized创建的时候一个互斥的对象锁&#xff0c;每次只有一个线程可以获取该锁。 其底层主要是基于Monitor实现的&#xff0c;在对象的对象头中存储了MarkWord存储的就是Monitor的地址。 对象的内存结构 对象在内存中存储主要分为三个部分&#xff1a…

聊一聊大模型 | 京东云技术团队

事情还得从ChatGPT说起。 2022年12月OpenAI发布了自然语言生成模型ChatGPT&#xff0c;一个可以基于用户输入文本自动生成回答的人工智能体。它有着赶超人类的自然对话程度以及逆天的学识。一时间引爆了整个人工智能界&#xff0c;各大巨头也纷纷跟进发布了自家的大模型&#…

Siamese网络与匈牙利算法在目标跟踪中的研究与应用

1. 引言 目标跟踪是计算机视觉领域中的一个重要研究方向&#xff0c;广泛应用于视频监控、智能交通、人机交互等领域。随着深度学习技术的不断发展&#xff0c;Siamese网络和匈牙利算法在目标跟踪领域的应用逐渐受到关注。本文将对Siamese网络与匈牙利算法以及其在目标…