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

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程序中&#xff0c;普通变量使用栈内存&#xff0c;为函数运行时专用&#xff0c;结束后会自动释放&#xff0c;无须考虑内存释放问题。 但堆内存是共用的&#xff0c;其使用是通过指针变量的new来分配&#xff0c;使用delete来释放&#xff0c;因指针使用方便…...

Flutter 核心原理 - UI 框架(UI Framework)

Flutter 既能保证很高的开发效率&#xff0c;又能获得很好的性能。 这两年 Flutter 技术热度持续提高&#xff0c;整个 Flutter 生态和社区也发生了翻天覆地的变化。目前Flutter 稳定版发布到了3.0&#xff0c;现在已经支持移动端、Web端和PC端&#xff0c;通过Flutter 开发的…...

Hive优化

工作中涉及到优化部分不多&#xff0c;下面的一些方案可能会缺少实际项目支撑&#xff0c;这里主要是为了完备一下知识体系。 参考的hive参数管理文档地址&#xff1a;https://cwiki.apache.org/confluence/display/Hive/ConfigurationProperties 对于Hive优化&#xff0c;可以…...

React 的 diff 算法

React 的 diff 算法的演进。 在 React 16 之前&#xff0c;React 使用的是称为 Reconciliation 的 diff 算法。Reconciliation 算法通过递归地比较新旧虚拟 DOM 树的每个节点&#xff0c;找出节点的差异&#xff0c;并将这些差异应用到实际的 DOM 上。整个过程是递归的&#x…...

综合知识篇07-软件架构设计考点(2024年软考高级系统架构设计师冲刺知识点总结系列文章)

专栏系列文章: 2024高级系统架构设计师备考资料(高频考点&真题&经验)https://blog.csdn.net/seeker1994/category_12593400.html案例分析篇00-【历年案例分析真题考点汇总】与【专栏文章案例分析高频考点目录】(2024年软考高级系统架构设计师冲刺知识点总结-案例…...

【GPT-SOVITS-05】SOVITS 模块-残差量化解析

说明&#xff1a;该系列文章从本人知乎账号迁入&#xff0c;主要原因是知乎图片附件过于模糊。 知乎专栏地址&#xff1a; 语音生成专栏 系列文章地址&#xff1a; 【GPT-SOVITS-01】源码梳理 【GPT-SOVITS-02】GPT模块解析 【GPT-SOVITS-03】SOVITS 模块-生成模型解析 【G…...

Flutter第四弹:Flutter图形渲染性能

目标&#xff1a; 1&#xff09;Flutter图形渲染性能能够媲美原生&#xff1f; 2&#xff09;Flutter性能优于React Native? 一、Flutter图形渲染原理 1.1 Flutter图形渲染原理 Flutter直接调用Skia。 Flutter不使用WebView&#xff0c;也不使用操作系统的原生控件,而是…...

[氮化镓]GaN中质子反冲离子的LET和射程特性

这篇文件是一篇关于氮化镓&#xff08;GaN&#xff09;中质子反冲离子的线性能量转移&#xff08;LET&#xff09;和射程特性的研究论文&#xff0c;发表在《IEEE Transactions on Nuclear Science》2021年5月的期刊上。论文的主要内容包括&#xff1a; 研究背景&#xff1a;氮…...

【项目】C++ 基于多设计模式下的同步异步日志系统

前言 一般而言&#xff0c;业务的服务都是周而复始的运行&#xff0c;当程序出现某些问题时&#xff0c;程序员要能够进行快速的修复&#xff0c;而修复的前提是要能够先定位问题。 因此为了能够更快的定位问题&#xff0c;我们可以在程序运行过程中记录一些日志&#xff0c;通…...

安卓国产百度网盘与国外云盘软件onedrive对比

我更愿意使用国外软件公司的产品&#xff0c;而不是使用国内百度等制作的流氓软件。使用这些国产软件让我不放心&#xff0c;他们占用我的设备大量空间&#xff0c;在我的设备上推送运行各种无用的垃圾功能。瞒着我&#xff0c;做一些我不知道的事情。 百度网盘安装包大小&…...

健身·健康行业Web3新尝试:MATCHI

随着区块链技术进入主流&#xff0c;web3 运动已经开始彻底改变互联网&#xff0c;改写从游戏到金融再到艺术的行业规则。现在&#xff0c;MATCHI的使命是颠覆健身行业。 MATCHI是全球首个基于Web3的在线舞蹈健身游戏和全球首个Web3舞蹈游戏的发起者&#xff0c;注册于新加坡&a…...

VB.NET高级面试题:什么是 VB.NET?与 Visual Basic 6.0 相比有哪些主要区别?

什么是 VB.NET&#xff1f;与 Visual Basic 6.0 相比有哪些主要区别&#xff1f; VB.NET是一种面向对象的编程语言&#xff0c;是微软公司推出的.NET平台上的一种编程语言&#xff0c;用于构建Windows应用程序、Web应用程序和Web服务等。它是Visual Basic的后续版本&#xff0…...

30.HarmonyOS App(JAVA)鸿蒙系统app多线程任务分发器

HarmonyOS App(JAVA)多线程任务分发器 打印时间&#xff0c;记录到编辑框textfield信息显示 同步分发&#xff0c;异步分发&#xff0c;异步延迟分发&#xff0c;分组任务分发&#xff0c;屏蔽任务分发&#xff0c;多次任务分发 参考代码注释 场景介绍 如果应用的业务逻辑比…...

伺服电机编码器的分辨率指得是什么?

伺服电机编码器的分辨率是伺服电机编码器的重要参数。 一般来说&#xff0c;具体的伺服电机编码器型号可以找到对应的分辨率值。 伺服电机编码器的分辨率和精度不同&#xff0c;但也有一定的关系。 伺服电机编码器的分辨率是多少&#xff1f; 1、伺服编码器&#xff08;同步伺…...

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名片联系&#xff0c;源码不免费&#xff0c;尊重创作&#xff0c;尊重劳动 项目编号078 1.开发环境android stuido jdk1.8 eclipse mysql tomcat 2.功能介绍 安卓端&#xff1a; 1.注册登录 2.查看博客列表 3.查看博客详情 4.评论博客&#xff0c; 5.…...

【GPT-SOVITS-01】源码梳理

说明&#xff1a;该系列文章从本人知乎账号迁入&#xff0c;主要原因是知乎图片附件过于模糊。 知乎专栏地址&#xff1a; 语音生成专栏 系列文章地址&#xff1a; 【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对象&#xff0c;它用于跟踪经过的时间。这在动画和物理模拟中很有用。 2. 创建场景: const scene new THREE.Scene();这行代码创建了一个新的3D场景。所有的物体&#xff08;如模型、灯…...

将FastSAM中的TextPrompt迁移到MobileSAM中

本博文简单介绍了SAM、FastSAM与MobileSAM,主要关注于TextPrompt功能的使用。从性能上看MobileSAM是最实用的,但其没有提供TextPrompt功能,故而参考FastSAM中的实现,在MobileSAM中嵌入TextPrompt类。并将TextPrompt能力嵌入到MobileSAM官方项目提供的gradio.py部署代码中,…...

谷歌浏览器插件

项目中有时候会用到插件 sync-cookie-extension1.0.0&#xff1a;开发环境同步测试 cookie 至 localhost&#xff0c;便于本地请求服务携带 cookie 参考地址&#xff1a;https://juejin.cn/post/7139354571712757767 里面有源码下载下来&#xff0c;加在到扩展即可使用FeHelp…...

day52 ResNet18 CBAM

在深度学习的旅程中&#xff0c;我们不断探索如何提升模型的性能。今天&#xff0c;我将分享我在 ResNet18 模型中插入 CBAM&#xff08;Convolutional Block Attention Module&#xff09;模块&#xff0c;并采用分阶段微调策略的实践过程。通过这个过程&#xff0c;我不仅提升…...

IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)

文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...

MySQL 主从同步异常处理

阅读原文&#xff1a;https://www.xiaozaoshu.top/articles/mysql-m-s-update-pk MySQL 做双主&#xff0c;遇到的这个错误&#xff1a; Could not execute Update_rows event on table ... Error_code: 1032是 MySQL 主从复制时的经典错误之一&#xff0c;通常表示&#xff…...

鸿蒙HarmonyOS 5军旗小游戏实现指南

1. 项目概述 本军旗小游戏基于鸿蒙HarmonyOS 5开发&#xff0c;采用DevEco Studio实现&#xff0c;包含完整的游戏逻辑和UI界面。 2. 项目结构 /src/main/java/com/example/militarychess/├── MainAbilitySlice.java // 主界面├── GameView.java // 游戏核…...

LangChain【6】之输出解析器:结构化LLM响应的关键工具

文章目录 一 LangChain输出解析器概述1.1 什么是输出解析器&#xff1f;1.2 主要功能与工作原理1.3 常用解析器类型 二 主要输出解析器类型2.1 Pydantic/Json输出解析器2.2 结构化输出解析器2.3 列表解析器2.4 日期解析器2.5 Json输出解析器2.6 xml输出解析器 三 高级使用技巧3…...

Python的__call__ 方法

在 Python 中&#xff0c;__call__ 是一个特殊的魔术方法&#xff08;magic method&#xff09;&#xff0c;它允许一个类的实例像函数一样被调用。当你在一个对象后面加上 () 并执行时&#xff08;例如 obj()&#xff09;&#xff0c;Python 会自动调用该对象的 __call__ 方法…...

手动给中文分词和 直接用神经网络RNN做有什么区别

手动分词和基于神经网络&#xff08;如 RNN&#xff09;的自动分词在原理、实现方式和效果上有显著差异&#xff0c;以下是核心对比&#xff1a; 1. 实现原理对比 对比维度手动分词&#xff08;规则 / 词典驱动&#xff09;神经网络 RNN 分词&#xff08;数据驱动&#xff09…...

C# WPF 左右布局实现学习笔记(1)

开发流程视频&#xff1a; https://www.youtube.com/watch?vCkHyDYeImjY&ab_channelC%23DesignPro Git源码&#xff1a; GitHub - CSharpDesignPro/Page-Navigation-using-MVVM: WPF - Page Navigation using MVVM 1. 新建工程 新建WPF应用&#xff08;.NET Framework) 2.…...

使用VMware克隆功能快速搭建集群

自己搭建的虚拟机&#xff0c;后续不管是学习java还是大数据&#xff0c;都需要集群&#xff0c;java需要分布式的微服务&#xff0c;大数据Hadoop的计算集群&#xff0c;如果从头开始搭建虚拟机会比较费时费力&#xff0c;这里分享一下如何使用克隆功能快速搭建一个集群 先把…...