C++特性——智能指针

embedded/2025/3/18 13:13:48/

为什么需要智能指针

对于定义的局部变量,当作用域结束之后,就会自动回收,这没有什么问题。
当时用new delete的时候,就是动态分配对象的时候,如果new了一个变量,但却没有delete,这会造成内存泄露。
特别是当大型项目,会使用多个指针指向同一块内存区域的时候,什么时候释放这块指针所指向的内存区域就成了一个问题。
智能指针就是解决这个问题的办法,他的思想就是当你定义了一个智能指针,可以像普通指针一样使用*⃣️来获取里面的内容,当用其他的智能指针再次指向这块区域的时候,会有一个计数器。当所有的智能指针都被标记为不再使用的时候,这个计数器清零,这块指针所指向的内存也就被释放。

什么是动态分配的对象? 是指在程序运行时(而非编译时)在堆(heap)内存中分配的对象。

注意

在使用智能指针的时候,一定要避免使用delete,可能会引发未定义的行为,就让系统自己处理。
unique_ptr性能很好,不支持复制,唯一控制权;shared_ptr支持多个指针指向同一块内存并计数,资源消耗大。
任何时候都推荐使用unique_ptr,而shared_ptr当多个函数

shared_ptr

引入#include <memory>
用法:shared _ptr<T> p = make_shared<T>()或者大括号的初始方法shared_ptr<T> p {fp, close_file}
例如shared _ptr<int> p = make_shared<int>(100)的意思就是定义了一个指向存储内容为100的动态内存的共享指针p。此时p.use_count() 引用计数为1。
当定义其他的共享指针p1=p时,表示p1也指向了int类型的100的这块内存,同理如果是对象,不会再构造一次,因为指向的是同一块东西。此时再使用p.use_count()或者p1.use_count()得到的计数结果都是2。
p.reset()就表示重置p指向的内容,此时引用计数会减1,当p1.reset()p1也重置之后,引用计数为0,这块内存被释放。

额外补充

  1. p.reset()这个用法还可以在括号里p.reset(new int)代表指向一个新的int内存,旧的int内存减1
  2. 在新定义一个共享指针的时候,是可以对它的释放功能自定义的,可以自定义为其他的功能,例如下图将释放功能自定义为文件关闭函数。当引用计数为0的时候,就可以自动关闭文件。
    在这里插入图片描述
  3. 别名 shared_ptr<example_class> p1 {p, &(p->bar)} p1是p的别名

unique_ptr

引入#include <memory>
用法:unique_ptr<int> p = make_unique<int>(100)
unique_ptr就不存在复制这样的功能,p独享这一块资源,不能和别的指针共享。
当作用域结束之后,unique_ptr指向的资源就会释放,即使它是用的new delete来创建的。
可以使用p.get()获取裸指针。
同样的,可以使用p.reset()来重置unique_ptr使其指向nullptr。也可以p.reset(new class)来让这个unique_ptr指向一个新的类。
可以使用p.release()来释放p对这块资源的控制权,会返回一个裸指针。unique_ptr中是没有复制这么一说的,也就不存“=”的赋值。但是可以传递:通过unique<exapmle_class> p1 (p.release())或者是利用move,即unique_ptr<example_class> p1(p.move())
unnique_ptr可以自定义分配函数和自定义释放函数,eg:
在这里插入图片描述

unique_ptr的函数绑定是在编译时就绑定了,这个函数成为了unique_ptr实例的一部分,而shared_ptr则是运行时绑定。

在函数之间的unique_ptr传递

指针在函数之间的传递难免不会发生复制,例如实参作为输入进入函数之后,函数可能会复制一份进入函数体。
解决办法:

  1. 函数的形参是一个unique_ptr的引用
  2. 只传递所指向的资源例如传入*p,接收也是一个int& p。
  3. 利用p.get()或者是move(),这样会传递一个裸指针到函数里去。

weak_ptr

weak_ptr是与shared_ptr成双成对的,它只能作为一个观察者
对资源的引用是非拥有式的,因此不能控制资源的释放。当想使用weak_ptr来烦我跟对象,需要使用shared_ptr<int> spt = wp.lock()是会返回一个shared_ptr,然后就可以正常的使用*来访问了


http://www.ppmy.cn/embedded/173597.html

相关文章

每日学习Java之一万个为什么

场景启动器&#xff1a;starter 参考常见启动器 默认配置 官网默认值 依赖 见官网 / pom父依赖 注解 SpringBootApplication&#xff1a;启动自动装配&#xff0c;配合 main SpringApplication.run&#xff08;.class,args&#xff09; SpringBootTest&#xff1a;Spri…

MySQL数据库备份工具:binlog详细操作与实战指南

MySQL的binlog&#xff08;二进制日志&#xff09;是MySQL数据库中非常重要的日志文件&#xff0c;它记录了所有对数据库的修改操作&#xff08;如INSERT、UPDATE、DELETE等&#xff09;。通过 binlog&#xff0c;我们可以实现数据恢复、主从复制、数据审计等功能。因此&#x…

【多线程】单例模式

文章目录 1. 单例模式1.1 什么是单例模式1.2 为什么使用单例模式1.3 实现单例模式1.3.1 饿汉模式1.3.1 懒汉模式 1. 单例模式 1.1 什么是单例模式 单例模式是一种创建型设计模式&#xff0c;它确保一个类只有一个实例&#xff0c;并提供一个全局访问点来访问该实例。 单例 单…

vue2:el-table列中文字前面加icon图标的两种方式

1、文字前面加icon <el-table-column label="姓名" align="left" prop="nickName"><template #default="{ row }"><i v-if="row.sync" class="el-icon-lock"></i><span>{{ row.nic…

网络安全与七层架构

网络安全与七层架构 随着互联网技术的迅猛发展&#xff0c;网络安全问题日益凸显。网络安全不仅影响到个人用户的信息安全&#xff0c;更是企业及国家安全的重要组成部分。而七层架构&#xff08;OSI模型&#xff09;为网络通信提供了理论支撑&#xff0c;能够有效地帮助我们理…

ImGui 学习笔记(五) —— 字体文件加载问题

ImGui 加载字体文件的函数似乎存在编码问题&#xff0c;这一点可能跟源文件的编码也有关系&#xff0c;我目前源文件编码是 UTF-16。 当参数中包含中文字符时&#xff0c;ImGui 内部将字符转换为宽字符字符集时候&#xff0c;采用的 MultiByteToWideChar API 参数不太对&#…

处理变长的时间序列

pytorch中torch.nn.utils.rnn相关sequence的pad和pack操作 官网…torch.nn.utils.rnn.pack_padded_sequence 知乎pack_padded_sequence 和 pad_packed_sequence 结论 ✅ pack_padded_sequence 是最好的方法&#xff08;避免无效计算&#xff0c;提升性能&#xff09; &#x…

java 动态赋值写入word模板

最近工作中&#xff0c;客户给提供了word模板&#xff0c;要求动态赋值到word模板中&#xff0c;查阅相关资料&#xff0c;最终完成了需求&#xff0c;希望也可以帮助到大家&#xff01; 例如表格如下&#xff1a; 第一步&#xff1a;在word模板中&#xff0c;把需要动态赋值的…