当前位置: 首页 > news >正文

std::shared_ptr与std::make_unique在类函数中的使用

在最近学习cartographer算法的时候,发现源码中大量的使用了std::shared_ptr与std::make_unique,对于这些东西之前不是很了解,为了更好的理解源代码,因此简单学习了一下这块内容的使用,在这里简单记个笔记。

std::shared_ptr

shared_ptr是一种智能指针(smart pointer),作用有如同指针,但会记录有多少个shared_ptrs共同指向一个对象。这便是所谓的引用计数(reference counting)。
一旦最后一个这样的指针被销毁,也就是一旦某个对象的引用计数变为0,这个对象会被自动删除。

其创建方式主要包含以下几种:
1、空shared_ptr

shared_ptr <T>  ptr;

2、使用new创建

shared_ptr<T> ptr(new T());

3、使用复制构造函数,或者重载=构造

shared_ptr<T> ptr1(new T()); 
shared_ptr<T> ptr2(ptr1);

示例:

shared_ptr<int> sp(new int(10));                //一个指向整数的shared_ptr    
assert(sp.unique());                            //现在shared_ptr是指针的唯一持有者     
shared_ptr<int> sp2 = sp;                       //第二个shared_ptr,拷贝构造函数     
assert(sp == sp2 && sp.use_count() == 2);       //两个shared_ptr相等,指向同一个对象,引用计数为2    
*sp2 = 100;                                     //使用解引用操作符修改被指对象    
assert(*sp == 100);                             //另一个shared_ptr也同时被修改     
sp.reset();                                     //停止shared_ptr的使用    
assert(!sp); 

有些东西不是完全理解,先放这儿,后面看得多了写的多了自然就理解了。

此外,与shared_ptr相反的还有unique_ptr,它的区别在于unique_ptr实现独占式拥有(exclusive ownership)或严格拥有(strict ownership)概念,保证同一时间内只有一个智能指针可以指向该对象。它对于避免资源泄露(resourece leak)——例如“以new创建对象后因为发生异常而忘记调用delete”——特别有用。

std::make_unique

std::make_unique 是 C++11 标准引入的一个模板函数,用于动态分配指定类型的内存,并返回一个指向分配内存的唯一指针 (即 std::unique_ptr)。

std::make_unique 的语法如下:

template<typename T, typename... Args>
std::unique_ptr<T> make_unique(Args&&... args);

其中,T 是指定的类型,Args 是可变长模板参数包,用于传递给指定类型的构造函数的参数。在调用 std::make_unique 时,通过 Args 包传入构造函数的参数会被转发给类型 T 的构造函数,以生成相应的对象实例。该函数返回的指针是一个 std::unique_ptr 类型,表示一个拥有指向动态内存的所有权的对象。

为了方便理解std::shared_ptr与std::make_unique,我们在这里举个例子:

例1

#include "ros/ros.h"  
#include "std_msgs/String.h"
using namespace std;class A {
public://std::shared_ptr<B> pointer;~A() {std::cout << "A was destroyed" << std::endl;}void printdata(){std::cout << "print A class data" << std::endl;}
};class share_test
{public:share_test();ros::Subscriber data_sub;void init();private:std::shared_ptr<A> a;void dataCallback(const std_msgs::String::ConstPtr &msg);
};
share_test::share_test()
{ros::NodeHandle n;ros::NodeHandle private_nh("~");data_sub = n.subscribe<std_msgs::String>("/data_pub",1,&share_test::dataCallback,this);
}void share_test::init()
{a = std::make_unique<A>();//std::shared_ptr<A> a = std::make_shared<A>();
}void share_test::dataCallback(const std_msgs::String::ConstPtr &msg)
{a->printdata();
}
int main(int argc, char **argv)  
{ros::init(argc, argv, "share_test");  share_test share_test;share_test.init();ros::spin();  return 0;
}

在上述函数中,定义了两个类函数A以及share_test,在函数初始化中我们初始化了share_test类,同时在share_test中声明了一个shared_ptr指针:

std::shared_ptr<A> a;

注意这里创建的是一个空指针,上述创建方法中第一种。然后我们在下面的init函数中使用make_unique将其创建为动态分配的智能指针:

a = std::make_unique<A>();

此时,原来的空指针就变成了指向类A的智能指针。这里有个问题,在《C++ 的 make_unique》这篇博客中使用:

auto a = std::make_unique<A>();

的方式建立了指向A的智能指针时,a的指针类型为unique_ptr,但是这里我初始化时将其初始化为shared_ptr似乎也是一样的?不是很理解。

在完成这一步之后,就有了一个指向class A的智能指针。然后我们就可以调用class A中的相关函数,例如这里我们在订阅data_pub的回调函数中引用了A的print函数,编译运行后新开一个终端输入:

rostopic pub -1 /data_pub std_msgs/String "data: 'SSS'"

就可以在节点这边的终端显示如下输出:
在这里插入图片描述
可以看到这里打印出了class A中的打印输出。通过这种指针的方式我们可以很容易的引用一些其他类函数进行需求的解算

例2

再看一个新的例子:

#include "ros/ros.h"  
#include "std_msgs/String.h"
using namespace std;class C
{
public:double input_1;string input_2;C(double data1,string data2){std::cout << "data1 is:" << data1 << std::endl;std::cout << "data2 is:" << data2 << std::endl;input_1 = data1;input_2 = data2;}void printdata(){std::cout << "print C class data" << std::endl;std::cout << "input_1 is:" << input_1 << std::endl;std::cout << "input_2 is:" << input_2 << std::endl;}~C() {std::cout << "C was destroyed" << std::endl;}
};class share_test
{public:share_test();ros::Subscriber data_sub;void init();private:std::shared_ptr<C> c;std::shared_ptr<C> c2;void dataCallback(const std_msgs::String::ConstPtr &msg);
};
share_test::share_test()
{ros::NodeHandle n;ros::NodeHandle private_nh("~");data_sub = n.subscribe<std_msgs::String>("/data_pub",1,&share_test::dataCallback,this);
}void share_test::init()
{c = std::make_unique<C>(1,"abc");c2 = std::make_unique<C>(2,"abcd");//std::shared_ptr<A> a = std::make_shared<A>();
}void share_test::dataCallback(const std_msgs::String::ConstPtr &msg)
{c->printdata();c2->printdata();
}
int main(int argc, char **argv)  
{ros::init(argc, argv, "share_test");  share_test share_test;share_test.init();ros::spin();  return 0;
}

这里与上面的例子略有不同,这里的calss C定义了一个初始化函数,需要传递两个参数,同时在它的print函数中会打印这两个参数。而在class share_test中创建了两个指针:

    std::shared_ptr<C> c;std::shared_ptr<C> c2;

随后我们再次使用make_unique创建了两个指向class C的智能指针:

    c = std::make_unique<C>(1,"abc");c2 = std::make_unique<C>(2,"abcd");

编译运行这个程序,终端会显示如下:
在这里插入图片描述
可以看到这里输出了4条打印,这是因为share_test::init()函数初始化了两个智能指针,class C这个类作为模板类被使用了两次。

而后,我们再次触发一下subscriber回调函数,可以显示打印如下:
在这里插入图片描述
到这里执行了两次打印调用:

c->printdata();
c2->printdata();

这两个智能指针虽然是指向了同一个模板类,但是由于我们在创建的时候传参是不一样的,因此它们的打印结果也是不一样的,这个就是模板类与智能指针的好处了,通常我们只需要定一一个类函数,然后通过这样一个make_unique的方式创建一个智能指针,就可以使用它里面的一些函数,同时,由于它的指针是独享的,因此我虽然两个指针指向的是同一个类,但是由于类初始化时传递的参数不一致,最后得到的结果也是不一致的,这就极大的便利了一些重复性类函数的使用,例如在cartographer中,使用的子图的概念,就是通过类函数与指针的形式实现的。

参考:
std::shared_ptr 详解
shared_ptr(共享指针)使用总结
C++11新特性之十三:std::make_unique和std::make_shared
C++ 的 make_unique(含 C++ 代码示例)

相关文章:

std::shared_ptr与std::make_unique在类函数中的使用

在最近学习cartographer算法的时候&#xff0c;发现源码中大量的使用了std::shared_ptr与std::make_unique&#xff0c;对于这些东西之前不是很了解&#xff0c;为了更好的理解源代码&#xff0c;因此简单学习了一下这块内容的使用&#xff0c;在这里简单记个笔记。 std::shar…...

flutter 局部view更新,dialog更新进度,dialog更新

局部更新有好几种方法&#xff0c;本次使用的是 StatefulBuilder 定义 customState去更新对话框内容 import package:flutter/cupertino.dart; import package:flutter/material.dart;class ProgressDialog {final BuildContext context;BuildContext? dialogContext;double _…...

Lombok:@Delegate优化代码利器

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 目录 一、Delegate介绍 二、示例 三、使用场景 四、使用注意事项 总结 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一、Delegate介绍 Dele…...

【C语言】对称密码——栅栏的加密和解密

栅栏密码的原理&#xff1a; 栅栏层数n ①把将要传递的信息中的字母交替排成上下n行。 ②再将下面每一行字母排依次在上面一行的后边&#xff0c;从而形成一段密码。 ③例如&#xff1a;栅栏层数为2 明文&#xff1a;THE LONGEST DAY MUST HAVE AN END 加密&#xff1a; …...

一、rv1126开发之视频输入和视频编码

RV1126 H264/HEVC编码流程 一、RV1126编码的流程图&#xff1a; 二、每个代码模块详细讲解 2.1. VI模块的创建 VI模块的初始化&#xff1a;关键在于VI_CHN_ATTR_S结构体&#xff0c;这个结构体是VI设置的结构体。这个结构体的成员变量包括&#xff1a;pcVideoNode&#xff0…...

4.1 用源文件写汇编代码

汇编语言 1. 源程序 1.1 伪指令 汇编指令是有对应的机器码的指令&#xff0c;可以被编译为机器指令&#xff0c;最终为CPU所执行伪指令没有对应的机器指令&#xff0c;最终不被CPU所执行伪指令是由编译器来执行的指令&#xff0c;编译器根据伪指令来进行相关的编译工作 1.2…...

Linux TCP参数——tcp_abort_on_overflow

文章目录 tcp_abort_on_overflow全连接队列是什么&#xff1f;如何改变队列大小&#xff1f;内核源码流程命令查看总结 tcp_abort_on_overflow 英文翻译理解&#xff1a;溢出中止 所以&#xff0c;溢出指的是什么溢出&#xff1f; Linux中会维护socket全连接队列&#xff0c;所…...

jupyter notebook设置代码提示方法

在命令行运行以下代码&#xff1a; pip install jupyter_contrib_nbextensionsjupyter contrib nbextension install --userpip install jupyter_nbextensions_configuratorjupyter nbextensions_configurator enable --user &#xff08;有时安装第一行后会自动执行第二行&a…...

Linux 一点查询资料

Linux 一点查询资料 Linux101 Linux入门教程 鸟哥的Linux私房菜 Harley Hahn’s Guide to Unix and Linux 文件管理 - cd, pwd, mkdir, rmdir, ls, cp, rm, mv, tar 文件检索 - cat, more, less, head, tail, file, find 输入输出控制 - 重定向, 管道, tee, xargs 文本处理 -…...

如何快速搭建一个完整的vue2+element-ui的项目-二

技术细节-继续配置 提示&#xff1a;你以为这样就完了吗,其实还有很多东西需要我们自己手写的 例如&#xff1a; element-ui的配置样式重置配置src使用的配置elinst配置axios异步请求的二次封转配置语言国际化配置(这个看需求,我这里就不用配置了)vuex的配置mixins的配置开发环…...

多语言LLM的状态:超越英语

多语言大语言模型的发展现状&#xff1a;超越英语 引言 据微软研究院的数据显示&#xff0c;世界上大约88%的语言&#xff0c;即12亿人的母语&#xff0c;缺乏对大型语言模型&#xff08;LLM&#xff09;的访问。这是因为大多数LLM都是以英语为中心的&#xff0c;即它们大多是…...

kafka什么情况下会认为发送失败进而去重试

在Kafka中&#xff0c;发送消息的过程是异步的&#xff0c;即消息后不会立即得到发送结果。Kafka会将消息添加到发送缓冲区&#xff0c;并立即返回一个成功的响应。因此&#xff0c;Kafka并不会直接知道消息是否成功发送到了目标主题的分区。 Kafka在以下情况下会认为发送失败…...

不满足软件包要求‘transformers==4.30.2‘, ‘sse-starlette

transformers4.30.2支持的SSE-Starlette版本是0.14.0...

C# 设置AutoScroll为true没效果的原因分析和解决办法

C#中添加tabControl 分页&#xff0c;将autoscroll设置为true发现缩小窗口没有滚动条效果。该问题出现后&#xff0c;检索发现也有很多人询问了该问题&#xff0c;但是都没有给出解决方案。 原因是内部button的属性Anchor设置为top、left、right、bottom导致的缩小界面窗口也没…...

<Senior High School Math>: inequality question

( 1 ) . o m i t (1). omit (1).omit ( 2 ) . ( a 2 − b 2 ) ( x 2 a 2 − y 2 b 2 ) ( x 2 y 2 ) − ( a 2 y 2 b 2 b 2 x 2 a 2 ) ≤ x 2 y 2 − 2 x y ( x − y ) 2 (2). (a^2-b^2)(\frac{x^2}{a^2} - \frac{y^2}{b^2})(x^2y^2)-(\frac{a^2y^2}{b^2}\frac{b^2x^2}{a^…...

详解Python中Pytest和Unittest的区别

昨天在群里面&#xff0c;有两个新手的小伙伴提问&#xff1a;Pytest 和 Unittest是Python中属于最常用的两个测试框架。那么他们有些什么区别呢&#xff1f; Playwright 为什么只给了Pytest的深度支持&#xff0c;而不是Unittest呢&#xff1f; 这是个好问题&#xff0c; 田辛…...

零基础入门多媒体音频(1)-音频基础

声音的本质是波动&#xff0c;波形图能直观体现声音的特征。我们常用于描述音频的属性有下面这些&#xff1a; 1.采样率&#xff1a;声音中每秒包含的采样点个数。 2.位宽&#xff1a;每个采样点需要多少个bit进行存储。 3.声道数&#xff1a;声音进行回放需要喇叭的个数。 4.频…...

40 道高频 C++ 面试、笔试题及答案

1. 什么是多态&#xff1f; 答案&#xff1a; 多态允许对象在运行时表现出不同的行为&#xff0c;具体取决于其类型。 2. 虚函数和纯虚函数之间的区别是什么&#xff1f; 答案&#xff1a; 虚函数可以被派生类重写&#xff0c;而纯虚函数必须被派生类实现&#xff0c;否则派生…...

【07】进阶html5

HTML5 包含两个部分的更新,分别是文档和web api 文档 HTML5 元素表 元素语义化 元素语义化是指每个 HTML 元素都代表着某种含义,在开发中应该根据元素含义选择元素 元素语义化的好处: 利于 SEO(搜索引擎优化)利于无障碍访问利于浏览器的插件分析网页新增元素 多媒体…...

Linux|centos7|postgresql数据库|yum和编译方式安装总结(全系版本)

一、 yum方式安装postgresql 这个是官方的yum源&#xff0c;包括postgresql的开发包&#xff0c;lib库什么的&#xff0c;很齐全&#xff0c;关键是包括pgbackrest yum install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-7-x86_64/pgdg-redhat-repo-la…...

Python|GIF 解析与构建(5):手搓截屏和帧率控制

目录 Python&#xff5c;GIF 解析与构建&#xff08;5&#xff09;&#xff1a;手搓截屏和帧率控制 一、引言 二、技术实现&#xff1a;手搓截屏模块 2.1 核心原理 2.2 代码解析&#xff1a;ScreenshotData类 2.2.1 截图函数&#xff1a;capture_screen 三、技术实现&…...

【位运算】消失的两个数字(hard)

消失的两个数字&#xff08;hard&#xff09; 题⽬描述&#xff1a;解法&#xff08;位运算&#xff09;&#xff1a;Java 算法代码&#xff1a;更简便代码 题⽬链接&#xff1a;⾯试题 17.19. 消失的两个数字 题⽬描述&#xff1a; 给定⼀个数组&#xff0c;包含从 1 到 N 所有…...

vscode(仍待补充)

写于2025 6.9 主包将加入vscode这个更权威的圈子 vscode的基本使用 侧边栏 vscode还能连接ssh&#xff1f; debug时使用的launch文件 1.task.json {"tasks": [{"type": "cppbuild","label": "C/C: gcc.exe 生成活动文件"…...

python如何将word的doc另存为docx

将 DOCX 文件另存为 DOCX 格式&#xff08;Python 实现&#xff09; 在 Python 中&#xff0c;你可以使用 python-docx 库来操作 Word 文档。不过需要注意的是&#xff0c;.doc 是旧的 Word 格式&#xff0c;而 .docx 是新的基于 XML 的格式。python-docx 只能处理 .docx 格式…...

解决本地部署 SmolVLM2 大语言模型运行 flash-attn 报错

出现的问题 安装 flash-attn 会一直卡在 build 那一步或者运行报错 解决办法 是因为你安装的 flash-attn 版本没有对应上&#xff0c;所以报错&#xff0c;到 https://github.com/Dao-AILab/flash-attention/releases 下载对应版本&#xff0c;cu、torch、cp 的版本一定要对…...

【从零开始学习JVM | 第四篇】类加载器和双亲委派机制(高频面试题)

前言&#xff1a; 双亲委派机制对于面试这块来说非常重要&#xff0c;在实际开发中也是经常遇见需要打破双亲委派的需求&#xff0c;今天我们一起来探索一下什么是双亲委派机制&#xff0c;在此之前我们先介绍一下类的加载器。 目录 ​编辑 前言&#xff1a; 类加载器 1. …...

【Elasticsearch】Elasticsearch 在大数据生态圈的地位 实践经验

Elasticsearch 在大数据生态圈的地位 & 实践经验 1.Elasticsearch 的优势1.1 Elasticsearch 解决的核心问题1.1.1 传统方案的短板1.1.2 Elasticsearch 的解决方案 1.2 与大数据组件的对比优势1.3 关键优势技术支撑1.4 Elasticsearch 的竞品1.4.1 全文搜索领域1.4.2 日志分析…...

用鸿蒙HarmonyOS5实现中国象棋小游戏的过程

下面是一个基于鸿蒙OS (HarmonyOS) 的中国象棋小游戏的实现代码。这个实现使用Java语言和鸿蒙的Ability框架。 1. 项目结构 /src/main/java/com/example/chinesechess/├── MainAbilitySlice.java // 主界面逻辑├── ChessView.java // 游戏视图和逻辑├──…...

ArcPy扩展模块的使用(3)

管理工程项目 arcpy.mp模块允许用户管理布局、地图、报表、文件夹连接、视图等工程项目。例如&#xff0c;可以更新、修复或替换图层数据源&#xff0c;修改图层的符号系统&#xff0c;甚至自动在线执行共享要托管在组织中的工程项。 以下代码展示了如何更新图层的数据源&…...

以太网PHY布局布线指南

1. 简介 对于以太网布局布线遵循以下准则很重要&#xff0c;因为这将有助于减少信号发射&#xff0c;最大程度地减少噪声&#xff0c;确保器件作用&#xff0c;最大程度地减少泄漏并提高信号质量。 2. PHY设计准则 2.1 DRC错误检查 首先检查DRC规则是否设置正确&#xff0c;然…...