C++ 智能指针的使用
智能指针类型
在C++程序中,普通变量使用栈内存,为函数运行时专用,结束后会自动释放,无须考虑内存释放问题。 但堆内存是共用的,其使用是通过指针变量的new来分配,使用delete来释放,因指针使用方便,很容易让程序员上瘾,其代价是各种原因造成的内存泄露问题,如:
- 忘记使用delete释放指针变量
- 指针数组,没有释放成员指针的内存
- 指针指向一个新地址,原地址内容未释放
- 异常处理程序,跳过了 delete 语句,致使指针未释放
等等,对服务器应用程序来说,内存泄露常常是致命的。
C++11后,STL增加了智能指针类型,主要有
- std::shared_ptr,
- std::weak_ptr
- std::unique_ptr
智能指针是指针上的包装类,重载了*和>等运算符。智能指针类的对象看起来像普通指针。但是,与普通指针不同,在析构函数里释放了指针,因此无须担心忘记释放指针。
unique_ptr用法
unique_ptr是智能指针最简单形式。 unique_ptr指向1个内存对象,而且是指向这个对象的唯一指针,这样可以避免出错。 但尽量不要将unique_ptr做为参数传给第3方接口函数,以避免对方以复制指针的方式来使用它。

使用语法
#include <memory>
using namespace std;unique_ptr<A> ptr(new A(初始化参数));
// 或者使用make_unique<T>() 模板函数来初始化unique_ptr
unique_ptr<A> ptr = make_unique<A>(初始化参数);
如定义1个int 类型的unique_ptr
int a = 99; unique_ptr<int> ptr = make_unique<int>(a);// std::unique_ptr x(new int(99)); // *ptr为指向对象的值,ptr.get()为对象地址cout << *ptr << ", " << ptr.get() << endl;
手工释放
ptr.reset();
ptr.reset(new int(1)); // 释放后,重新指向新地址
指向数组
unique_ptr<int[]> x(new int[5]);
x[0]=10;
x[1]=11;
用途:代替普通指针,以避免忘记释放
void NotLeaky() {
std::unique_ptr x(new int(5));
... // lots of code
}
unique_ptr指向的对象A,只能被1个指针使用
unique_ptr<A> p1(new A); p1->printA(); //下面语句会报错unique_ptr<A> p2 = p1; p2->printA();
允许复制指针,但复制后原指针被释放
unique_ptr<A> p2 = move(p1); p2->printA(); // p2已将p1复制p1->printA(); // 报错,p1 已被释放。
定义1个指向类对象的unique_ptr
class Character {
public:string Name;Character(string name = "Frodo") : Name(name){cout << "Greeting: " << Name << endl; }~Character() {cout << "Deleting " << Name << endl; }void printName() { cout << "Name: " << Name << endl; }
};int main() {
unique_ptr<Character> GandalPtr = make_unique<Character>("Gandal");
GandalPtr->printName();
cout << GandalPtr.get() << endl;
return 0;
}
shared_ptr用法
Shared_ptr 指的是,允许多个ptr指向同1块内存,增加了1个reference 计数器
- 当1个新指针指向该内存,reference计数器加1
- 当1个指向从该内存移走后,reference 计数器减1
- 计数器为0时,则释放内存对象。
shared_ptr 适用于给函数传值,类对象引用等各类场景。

创建shared_ptr 指针
std::shared_ptr<int> p1; //不传入任何实参
std::shared_ptr<int> p2(nullptr); //传入空指针 nullptr
std::shared_ptr<int> p3(new int(10));
C++11 标准中还提供了 std::make_shared 模板函数,其可以用于初始化 shared_ptr 智能指针,例如:
// 指向int 数据
std::shared_ptr<int> p3 = std::make_shared<int>(10);
// 指向类对象
shared_ptr<Rectangle> p1(new Rectangle(10, 5));
p1->getArea() //访问成员
//调用拷贝构造函数复制指针
std::shared_ptr<int> p2(p1);
//或者 std::shared_ptr<int> p2 = p1;
用法示例
#include <iostream>
#include <memory>
using namespace std;int main()
{//构建 2 个智能指针std::shared_ptr<int> p1(new int(10));std::shared_ptr<int> p2(p1);//输出 p2 指向的数据cout << *p2 << endl;p1.reset();//引用计数减 1,p1为空指针if (p1) {cout << "p1 不为空" << endl;}else {cout << "p1 为空" << endl;}//以上操作,并不会影响 p2cout << *p2 << endl;//判断当前和 p2 同指向的智能指针有多少个cout << p2.use_count() << endl;return 0;
}
程序执行结果为:
10
p1 为空
10
1
weak_ptr 指针用法
weak_ptr不能单独使用,只能和 shared_ptr 类型指针搭配使用,区别是其内部无对象引用计数器。

使用方式:
(1) 先创建一个空 weak_ptr 指针,例如:
std::weak_ptr wp1;
将其指向 shared_ptr 指针变量,即与shared_ptr指向同1个内存对象
std::shared_ptr<int> sp (new int);
std::weak_ptr<int> wp3 (sp);
wp3与sp指向相同的内存区,由于 weak_ptr没有重载* 与->操作符,因此不能直接访问对象成员与方法。weak_ptr不会引起对象引用计数器的变化,如下
std::shared_ptr<int> sp1(new int(10));
std::shared_ptr<int> sp2(sp1);
std::weak_ptr<int> wp(sp2);
//输出和 wp 同指向的 shared_ptr 类型指针的数量cout << wp.use_count() << endl;
如果要访问weak_ptr指向对象的成员或方法,需要借助 lock() 函数,返回一个和 weak_ptr 同指向的 shared_ptr 类型的指针,通过其来访问对象成员。
//访问对象的getArea()方法
cout << wp.lock()->getArea() << endl;
// 或者采用下面的方式,更安全。
auto sp = wp.lock() ;
if (sp) {sp->getArea();
}
总结
为了避免C++程序产生内存泄露的风险,应该掌握 unique_ptr, shared_ptr, weak_ptr 3种智能指针类型的使用方式与应用场景,通过智能指针的特性来实现内存自动释放与回收。
相关文章:
C++ 智能指针的使用
智能指针类型 在C程序中,普通变量使用栈内存,为函数运行时专用,结束后会自动释放,无须考虑内存释放问题。 但堆内存是共用的,其使用是通过指针变量的new来分配,使用delete来释放,因指针使用方便…...
Flutter 核心原理 - UI 框架(UI Framework)
Flutter 既能保证很高的开发效率,又能获得很好的性能。 这两年 Flutter 技术热度持续提高,整个 Flutter 生态和社区也发生了翻天覆地的变化。目前Flutter 稳定版发布到了3.0,现在已经支持移动端、Web端和PC端,通过Flutter 开发的…...
Hive优化
工作中涉及到优化部分不多,下面的一些方案可能会缺少实际项目支撑,这里主要是为了完备一下知识体系。 参考的hive参数管理文档地址:https://cwiki.apache.org/confluence/display/Hive/ConfigurationProperties 对于Hive优化,可以…...
React 的 diff 算法
React 的 diff 算法的演进。 在 React 16 之前,React 使用的是称为 Reconciliation 的 diff 算法。Reconciliation 算法通过递归地比较新旧虚拟 DOM 树的每个节点,找出节点的差异,并将这些差异应用到实际的 DOM 上。整个过程是递归的&#x…...
综合知识篇07-软件架构设计考点(2024年软考高级系统架构设计师冲刺知识点总结系列文章)
专栏系列文章: 2024高级系统架构设计师备考资料(高频考点&真题&经验)https://blog.csdn.net/seeker1994/category_12593400.html案例分析篇00-【历年案例分析真题考点汇总】与【专栏文章案例分析高频考点目录】(2024年软考高级系统架构设计师冲刺知识点总结-案例…...
【GPT-SOVITS-05】SOVITS 模块-残差量化解析
说明:该系列文章从本人知乎账号迁入,主要原因是知乎图片附件过于模糊。 知乎专栏地址: 语音生成专栏 系列文章地址: 【GPT-SOVITS-01】源码梳理 【GPT-SOVITS-02】GPT模块解析 【GPT-SOVITS-03】SOVITS 模块-生成模型解析 【G…...
Flutter第四弹:Flutter图形渲染性能
目标: 1)Flutter图形渲染性能能够媲美原生? 2)Flutter性能优于React Native? 一、Flutter图形渲染原理 1.1 Flutter图形渲染原理 Flutter直接调用Skia。 Flutter不使用WebView,也不使用操作系统的原生控件,而是…...
[氮化镓]GaN中质子反冲离子的LET和射程特性
这篇文件是一篇关于氮化镓(GaN)中质子反冲离子的线性能量转移(LET)和射程特性的研究论文,发表在《IEEE Transactions on Nuclear Science》2021年5月的期刊上。论文的主要内容包括: 研究背景:氮…...
【项目】C++ 基于多设计模式下的同步异步日志系统
前言 一般而言,业务的服务都是周而复始的运行,当程序出现某些问题时,程序员要能够进行快速的修复,而修复的前提是要能够先定位问题。 因此为了能够更快的定位问题,我们可以在程序运行过程中记录一些日志,通…...
安卓国产百度网盘与国外云盘软件onedrive对比
我更愿意使用国外软件公司的产品,而不是使用国内百度等制作的流氓软件。使用这些国产软件让我不放心,他们占用我的设备大量空间,在我的设备上推送运行各种无用的垃圾功能。瞒着我,做一些我不知道的事情。 百度网盘安装包大小&…...
健身·健康行业Web3新尝试:MATCHI
随着区块链技术进入主流,web3 运动已经开始彻底改变互联网,改写从游戏到金融再到艺术的行业规则。现在,MATCHI的使命是颠覆健身行业。 MATCHI是全球首个基于Web3的在线舞蹈健身游戏和全球首个Web3舞蹈游戏的发起者,注册于新加坡&a…...
VB.NET高级面试题:什么是 VB.NET?与 Visual Basic 6.0 相比有哪些主要区别?
什么是 VB.NET?与 Visual Basic 6.0 相比有哪些主要区别? VB.NET是一种面向对象的编程语言,是微软公司推出的.NET平台上的一种编程语言,用于构建Windows应用程序、Web应用程序和Web服务等。它是Visual Basic的后续版本࿰…...
30.HarmonyOS App(JAVA)鸿蒙系统app多线程任务分发器
HarmonyOS App(JAVA)多线程任务分发器 打印时间,记录到编辑框textfield信息显示 同步分发,异步分发,异步延迟分发,分组任务分发,屏蔽任务分发,多次任务分发 参考代码注释 场景介绍 如果应用的业务逻辑比…...
伺服电机编码器的分辨率指得是什么?
伺服电机编码器的分辨率是伺服电机编码器的重要参数。 一般来说,具体的伺服电机编码器型号可以找到对应的分辨率值。 伺服电机编码器的分辨率和精度不同,但也有一定的关系。 伺服电机编码器的分辨率是多少? 1、伺服编码器(同步伺…...
WPF中使用LiveCharts绘制散点图
一、背景 这里的代码使用MVVM模式进行编写 二、Model public class DataPoint{public double X { get; set; }public double Y { get; set; }} 三、ViewModel public class ScatterChartViewModel{public SeriesCollection Series { get; set; }public ScatterChartViewMod…...
Android Studio实现内容丰富的安卓博客发布平台
获取源码请点击文章末尾QQ名片联系,源码不免费,尊重创作,尊重劳动 项目编号078 1.开发环境android stuido jdk1.8 eclipse mysql tomcat 2.功能介绍 安卓端: 1.注册登录 2.查看博客列表 3.查看博客详情 4.评论博客, 5.…...
【GPT-SOVITS-01】源码梳理
说明:该系列文章从本人知乎账号迁入,主要原因是知乎图片附件过于模糊。 知乎专栏地址: 语音生成专栏 系列文章地址: 【GPT-SOVITS-01】源码梳理 【GPT-SOVITS-02】GPT模块解析 【GPT-SOVITS-03】SOVITS 模块-生成模型解析 【G…...
数据结构大合集02——线性表的相关函数运算算法
函数运算算法合集02 顺序表的结构体顺序表的基本运算的实现1. 建立顺序表2. 顺序表的基本运算2.1 初始化线性表2. 2 销毁顺序表2.3 判断顺序表是否为空表2.4 求顺序表的长度2.5 输出顺序表2.6 按序号求顺序表中的元素2.7 按元素值查找2.8 插入数据元素2.9 删除数据元素 单链表的…...
threejs案例,与静态三角形网格的基本碰撞, 鼠标环顾四周并投球游戏
创建一个时钟对象: const clock new THREE.Clock();这行代码创建了一个新的THREE.Clock对象,它用于跟踪经过的时间。这在动画和物理模拟中很有用。 2. 创建场景: const scene new THREE.Scene();这行代码创建了一个新的3D场景。所有的物体(如模型、灯…...
将FastSAM中的TextPrompt迁移到MobileSAM中
本博文简单介绍了SAM、FastSAM与MobileSAM,主要关注于TextPrompt功能的使用。从性能上看MobileSAM是最实用的,但其没有提供TextPrompt功能,故而参考FastSAM中的实现,在MobileSAM中嵌入TextPrompt类。并将TextPrompt能力嵌入到MobileSAM官方项目提供的gradio.py部署代码中,…...
MySQL 隔离级别:脏读、幻读及不可重复读的原理与示例
一、MySQL 隔离级别 MySQL 提供了四种隔离级别,用于控制事务之间的并发访问以及数据的可见性,不同隔离级别对脏读、幻读、不可重复读这几种并发数据问题有着不同的处理方式,具体如下: 隔离级别脏读不可重复读幻读性能特点及锁机制读未提交(READ UNCOMMITTED)允许出现允许…...
【JVM】- 内存结构
引言 JVM:Java Virtual Machine 定义:Java虚拟机,Java二进制字节码的运行环境好处: 一次编写,到处运行自动内存管理,垃圾回收的功能数组下标越界检查(会抛异常,不会覆盖到其他代码…...
React Native在HarmonyOS 5.0阅读类应用开发中的实践
一、技术选型背景 随着HarmonyOS 5.0对Web兼容层的增强,React Native作为跨平台框架可通过重新编译ArkTS组件实现85%以上的代码复用率。阅读类应用具有UI复杂度低、数据流清晰的特点。 二、核心实现方案 1. 环境配置 (1)使用React Native…...
大语言模型如何处理长文本?常用文本分割技术详解
为什么需要文本分割? 引言:为什么需要文本分割?一、基础文本分割方法1. 按段落分割(Paragraph Splitting)2. 按句子分割(Sentence Splitting)二、高级文本分割策略3. 重叠分割(Sliding Window)4. 递归分割(Recursive Splitting)三、生产级工具推荐5. 使用LangChain的…...
基于Docker Compose部署Java微服务项目
一. 创建根项目 根项目(父项目)主要用于依赖管理 一些需要注意的点: 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件,否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...
第 86 场周赛:矩阵中的幻方、钥匙和房间、将数组拆分成斐波那契序列、猜猜这个单词
Q1、[中等] 矩阵中的幻方 1、题目描述 3 x 3 的幻方是一个填充有 从 1 到 9 的不同数字的 3 x 3 矩阵,其中每行,每列以及两条对角线上的各数之和都相等。 给定一个由整数组成的row x col 的 grid,其中有多少个 3 3 的 “幻方” 子矩阵&am…...
全志A40i android7.1 调试信息打印串口由uart0改为uart3
一,概述 1. 目的 将调试信息打印串口由uart0改为uart3。 2. 版本信息 Uboot版本:2014.07; Kernel版本:Linux-3.10; 二,Uboot 1. sys_config.fex改动 使能uart3(TX:PH00 RX:PH01),并让boo…...
ABAP设计模式之---“简单设计原则(Simple Design)”
“Simple Design”(简单设计)是软件开发中的一个重要理念,倡导以最简单的方式实现软件功能,以确保代码清晰易懂、易维护,并在项目需求变化时能够快速适应。 其核心目标是避免复杂和过度设计,遵循“让事情保…...
Android第十三次面试总结(四大 组件基础)
Activity生命周期和四大启动模式详解 一、Activity 生命周期 Activity 的生命周期由一系列回调方法组成,用于管理其创建、可见性、焦点和销毁过程。以下是核心方法及其调用时机: onCreate() 调用时机:Activity 首次创建时调用。…...
JavaScript基础-API 和 Web API
在学习JavaScript的过程中,理解API(应用程序接口)和Web API的概念及其应用是非常重要的。这些工具极大地扩展了JavaScript的功能,使得开发者能够创建出功能丰富、交互性强的Web应用程序。本文将深入探讨JavaScript中的API与Web AP…...
