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

C++ —— 智能指针 unique_ptr (上)

C++ —— 智能指针 unique_ptr (上)

  • 普通指针的不足
  • 普通指针的释放
  • 智能指针
  • 智能指针 unique_ptr
    • 智能指针初始化
    • 错误用法
    • get()方法返回裸指针
    • 智能指针不支持指针的运算(+、-、++、- -)

普通指针的不足

  • newnew [] 的内存需要用deletedelete []释放(堆区的内存一定要手工释放,否则会发生内存的泄露);
  • 程序员主观上的失误,忘记或漏掉释放;
  • 不确定何时释放。

普通指针的释放

  • 类内指针,在析构函数释放
  • 堆区的内存是C++内置数据类型,没有析构函数,只能delete释放;
  • new出来的类,还是得用delete释放。

智能指针

智能指针的目的:解决资源释放的问题。

智能指针使用步骤:

  • 智能指针是类模板,在栈上创建智能指针对象;
  • 把普通指针交给智能指针对象;
  • 智能指针对象过期时,调用析构函数释放普通指针的内存。

C++11标准的智能指针类型:unique_ptrshared_ptrweak_ptr

智能指针 unique_ptr

C++中,多个指针可以指向同一个对象。
unique_ptr 独享它指向的对象,也就是说,同时unique_ptr指向同一个对象,当这个unique_ptr销毁时,指向对象也随即被销毁

示例代码如下:

#include <iostream>
#include <memory> // 使用智能指针需要包含的头文件
using namespace std;class A {
public:string m_name;A() {cout << "A()" << endl;}A(const string& name): m_name(name) {cout << "A(const string&)" << endl;}~A() {cout << "~A()" << endl;}
};int main () {A* pa = new A("aaa");// delete pa;return 0;
}

因为没有delete,所以只有构造函数的日志信息,运行结果如下:

A(const string&)

使用智能指针unique_ptr来管理普通指针pa代码如下:

int main () {A* pa = new A("aaa");unique_ptr<A> pu_a(pa); // 间接地让智能指针 pu_a 来管理对象// 需要管理的普通指针的基类型是 A(也就是模板参数)// pa 是被管理的指针,pa 指向了 new 出来的对象的地址。return 0;
}

运行效果如下:

A(const string&)
~A()

可以看到,尽管没有使用delete语句,也销毁了A的对象。原因是:智能指针,它有析构函数,在它的析构函数中,使用了delete语句。

可以像使用普通指针一样去使用智能指针,代码如下:

int main () {A* pa = new A("aaa");// delete pa;unique_ptr<A> pu_a(pa);cout <<"m_name = " << (*pa).m_name << endl;cout << "m_name = " << pa->m_name << endl;cout << "m_name = " << (*pu_a).m_name << endl;cout << "m_name = " << pu_a->m_name << endl;return 0;
}

运行效果如下:

A(const string&)
m_name = aaa
m_name = aaa
m_name = aaa
m_name = aaa
~A()

智能指针初始化

  • 方法一(常用):
    unique_ptr<A> pu_a(new A("abcd")); // 分配内存并初始化
int main () {unique_ptr<A> pu_a(new A("abcd"));// new 返回的是对象的地址cout <<"m_name = " << (*pu_a).m_name << endl;cout << "m_name = " << pu_a->m_name << endl;return 0;
}

运行效果如下:

A(const string&)
m_name = abcd
m_name = abcd
~A()

  • 方法二:
    unique_ptr<A> p = make_unique<A>("abcd"); // C++14标准
    unique_ptr<int> p1=make_unique<int>(); // 数据类型为int
    unique_ptr<A> p2 = make_unique<A>(); // 数据类型为A,默认构造函数
    unique_ptr<A> p3 = make_unique<A>("abcd"); // 数据类型为A,一个参数的构造函数
    unique_ptr<A> p4 = make_unique<A>("abcd","efgh"); // 数据类型为A,两个参数的构造函数
  • 方法三(不推荐):
    A* p = new A("abcd");
    unique_ptr<A> pu (p); // 用已存在的地址初始化

错误用法

A* p = new a("abcd");
unique_ptr<A> pu1 = p; // 错误,不能把普通指针直接赋给智能指针。
unique_ptr<A> pu2 = new A("abcd"); // 错误,不能把普通指针直接赋给智能指针。
unique_ptr<A> pu3 = pu2; // 错误,不能用其它unique_ptr拷贝构造。
unique_ptr<A> pu4;
pu4 = pu1; // 错误,不能用 = 对 unique_ptr 进行赋值。
// 裸指针就是普通指针 pa就是普通指针,也叫裸指针
A* pa = new A("efgh");
unique_ptr<A> pu_a1(pa);
unique_ptr<A> pu_a2(pa);
unique_ptr<A> pu_a3(pa);
// 程序会异常退出,原因是:多个unique_ptr对象对同一块内存释放了多次

get()方法返回裸指针

int main () {A* pa = new A("efgh");unique_ptr<A> pu_a(pa);cout << "裸指针的值是:" << pa << endl;cout << "pu_a.get() = " << pu_a.get() << endl;// cout << pa->m_name << endl; // efgh// cout << pu_a.get()->m_name << endl; // efghcout << "pu_a的地址:" << &pu_a << endl;// pu_a是unique_ptr<A>模板类创建的对象,有自己的地址。// 自己的地址和它管理的原始指针的地址不是一回事return 0;
}

运行结果如下:

A(const string&)
裸指针的值是:0x557320cf6eb0
pu_a.get() = 0x557320cf6eb0
pu_a的地址:0x7ffde063e680
~A()

智能指针不支持指针的运算(+、-、++、- -)

感谢浏览,一起学习!

相关文章:

C++ —— 智能指针 unique_ptr (上)

C —— 智能指针 unique_ptr &#xff08;上&#xff09; 普通指针的不足普通指针的释放智能指针智能指针 unique_ptr智能指针初始化错误用法get()方法返回裸指针智能指针不支持指针的运算&#xff08;、-、、- -&#xff09; 普通指针的不足 new和new [] 的内存需要用delete和…...

技术 · 创作 · 生活 | 我的 2024 全面复盘

目录 &#x1f31f;2024年度总结&#xff1a;回顾、成长与突破&#x1f31f;&#x1f680; 一、技术成长与突破 &#x1f680;&#x1f517; 1. 深入区块链与智能合约&#x1f50d; 2. 探索新兴技术 ✍️ 二、创作与博客历程 ✍️&#x1f4d6; 1. 内容创作的演变&#x1f3c6;…...

表的增删改查(MySQL)

1. 表的增删改查 CRUD : Create(创建), Retrieve(读取)&#xff0c;Update(更新)&#xff0c;Delete&#xff08;删除&#xff09; 1.1 Create 语法&#xff1a; INSERT [INTO] table_name [(column [, column] ...)] VALUES (value_list) [, (value_list)] ...value_list:…...

【设计模式】JAVA 策略 工厂 模式 彻底告别switch if 等

【设计模式】JAVA 策略 工厂 模式 彻底告别switch if 等 目录 【设计模式】JAVA 策略 工厂 模式 彻底告别switch if 等 优势 适用场景 项目结构 关键代码 优势 消除 switch&#xff1a;将分支逻辑分散到独立的策略类中。 开闭原则&#xff1a;新增类型只需添加新的 TypeHa…...

基于Springboot用axiospost请求接收字符串参数为null的解决方案

问题 ​ 今天在用前端 post 请求后端时发现&#xff0c;由于是以 Json对象的形式传输的&#xff0c;后端用两个字符串形参无法获取到对应的参数值 前端代码如下&#xff1a; axios.post(http://localhost:8083/test/postParams,{a: 1, b:2} ,{Content-Type: application/jso…...

最长递增——蓝桥杯

1.题目描述 在数列 a1​,a2​,⋯,an​ 中&#xff0c;如果ai​<ai1​<ai2​<⋯<aj​&#xff0c;则称 ai​ 至 aj​ 为一段递增序列&#xff0c;长度为 j−i1。 定一个数列&#xff0c;请问数列中最长的递增序列有多长。 输入描述 输入的第一行包含一个整数 n。…...

【MFC】C++所有控件随窗口大小全自动等比例缩放源码(控件内字体、列宽等未调整) 20250124

MFC界面全自动等比例缩放 1.在初始化里 枚举每个控件记录所有控件rect 2.在OnSize里&#xff0c;根据当前窗口和之前保存的窗口的宽高求比例x、y 3.枚举每个控件&#xff0c;根据比例x、y调整控件上下左右,并移动到新rect struct ControlInfo {CWnd* pControl;CRect original…...

C#标准Mes接口框架(持续更新)

前言 由于近期我做了好几个客户的接入工厂Mes系统的需求。但是每个客户的Mes都有不同程度的定制需求&#xff0c;原有的代码复用难度其实很大。所以打算将整个接入Mes系统的框架单独拿出来作为一个项目使用&#xff0c;同时因为不同的设备接入同一个Mes系统&#xff0c;所以代…...

【Uniapp-Vue3】动态设置页面导航条的样式

1. 动态修改导航条标题 uni.setNavigationBarTitle({ title:"标题名称" }) 点击修改以后顶部导航栏的标题会从“主页”变为“动态标题” 2. 动态修改导航条颜色 uni.setNavigationBarColor({ backgroundColor:"颜色" }) 3. 动态添加导航加载动画 // 添加加…...

SQL 递归 ---- WITH RECURSIVE 的用法

SQL 递归 ---- WITH RECURSIVE 的用法 开发中遇到了一个需求&#xff0c;传递一个父类id&#xff0c;获取父类的信息&#xff0c;同时获取其所有子类的信息。 首先想到的是通过程序中去递归查&#xff0c;但这种方法着实孬了一点&#xff0c;于是想&#xff0c;sql能不能递归查…...

期权帮|如何利用股指期货进行对冲套利?

锦鲤三三每日分享期权知识&#xff0c;帮助期权新手及时有效地掌握即市趋势与新资讯&#xff01; 如何利用股指期货进行对冲套利&#xff1f; 对冲就是通过股指期货来平衡投资组合的风险。它分为正向与反向两种策略&#xff1a; &#xff08;1&#xff09;正向对冲&#xff…...

INCOSE需求编写指南-第1部分:介绍

第1部分&#xff1a;介绍Section 1: Introduction 1.1 目的和范围 Purpose and Scope 本指南专门介绍如何在系统工程背景下以文本形式表达需求和要求陈述。其目的是将现有标准&#xff08;如 ISO/IEC/IEEE 29148&#xff09;中的建议以及作者、主要贡献者和审稿员的最佳实践结…...

FFPlay命令全集合

FFPlay是以FFmpeg框架为基础&#xff0c;外加渲染音视频的库libSDL构建的媒体文件播放器。 ffplay工具下载并播放视频&#xff0c;可以辅助卡看流信息。 官网下载地址&#xff1a;http://ffmpeg.org/download.html#build-windows 下载build好的exe程序&#xff1a; 此处下载…...

Mono里运行C#脚本34—内部函数调用的过程

本文来分析Mono运行脚本时,会调用一些C实现的函数代码。 而这个过程又是怎么样实现的呢? 比如前面分析的脚本: IL_0000: call string class MonoEmbed::gimme() 在这里会调用C函数实现的MonoEmbed::gimme()函数。 而这个函数是在C程序内部实现,通过下面的代码来注册到运行…...

rust feature h和 workspace相关知识 (十一)

feature 相关作用和描述 在 Rust 中&#xff0c;features&#xff08;特性&#xff09; 是一种控制可选功能和依赖的机制。它允许你在编译时根据不同的需求启用或禁用某些功能&#xff0c;优化构建&#xff0c;甚至改变代码的行为。Rust 的特性使得你可以轻松地为库提供不同的…...

-bash: ./uninstall.command: /bin/sh^M: 坏的解释器: 没有那个文件或目录

终端报错&#xff1a; -bash: ./uninstall.command: /bin/sh^M: 坏的解释器: 没有那个文件或目录原因&#xff1a;由于文件行尾符不匹配导致的。当脚本文件在Windows环境中创建或编辑后&#xff0c;行尾符为CRLF&#xff08;即回车和换行&#xff0c;\r\n&#xff09;&#xf…...

【Redis】Redis入门以及什么是分布式系统{Redis引入+分布式系统介绍}

文章目录 介绍redis的引入 分布式系统单机架构应用服务和数据库服务分离【负载均衡】引入更多的应用服务器节点 单机架构 分布式是什么 数据库分离和负载均衡 理解负载均衡 数据库读写分离 引入缓存 数据库分库分表 引入微服务 介绍 The open source, in-memory data store us…...

C#高级:常用的扩展方法大全

1.String public static class StringExtensions {/// <summary>/// 字符串转List&#xff08;中逗 英逗分隔&#xff09;/// </summary>public static List<string> SplitCommaToList(this string data){if (string.IsNullOrEmpty(data)){return new List&…...

Consul持久化配置报错1067---consul_start

报错都是文件写的有问题或者格式问题&#xff0c;直接复制我的这个改改地址就行 先创建文本文件consul_start.txt--->再复制代码保存---->再把.txt改成.bat 持久化存储的地址在&#xff1a;mydata 注&#xff1a;D:\consul\consul_1.20.2_windows_386改成自己consul的…...

「 机器人 」扑翼飞行器控制策略浅谈

1. 研究背景 • 自然界中的蜂鸟以极高的机动能力著称,能够在短至0.2秒内完成如急转弯、快速加速、倒飞、躲避威胁等极限机动。这种表现对微型飞行器(Flapping Wing Micro Air Vehicles, FWMAVs)具有重要的仿生启示。 • 目前的微型飞行器距离自然生物的飞行能力仍有相当差距…...

模型参数、模型存储精度、参数与显存

模型参数量衡量单位 M&#xff1a;百万&#xff08;Million&#xff09; B&#xff1a;十亿&#xff08;Billion&#xff09; 1 B 1000 M 1B 1000M 1B1000M 参数存储精度 模型参数是固定的&#xff0c;但是一个参数所表示多少字节不一定&#xff0c;需要看这个参数以什么…...

《从零掌握MIPI CSI-2: 协议精解与FPGA摄像头开发实战》-- CSI-2 协议详细解析 (一)

CSI-2 协议详细解析 (一&#xff09; 1. CSI-2层定义&#xff08;CSI-2 Layer Definitions&#xff09; 分层结构 &#xff1a;CSI-2协议分为6层&#xff1a; 物理层&#xff08;PHY Layer&#xff09; &#xff1a; 定义电气特性、时钟机制和传输介质&#xff08;导线&#…...

UDP(Echoserver)

网络命令 Ping 命令 检测网络是否连通 使用方法: ping -c 次数 网址ping -c 3 www.baidu.comnetstat 命令 netstat 是一个用来查看网络状态的重要工具. 语法&#xff1a;netstat [选项] 功能&#xff1a;查看网络状态 常用选项&#xff1a; n 拒绝显示别名&#…...

相机从app启动流程

一、流程框架图 二、具体流程分析 1、得到cameralist和对应的静态信息 目录如下: 重点代码分析: 启动相机前,先要通过getCameraIdList获取camera的个数以及id,然后可以通过getCameraCharacteristics获取对应id camera的capabilities(静态信息)进行一些openCamera前的…...

基于Docker Compose部署Java微服务项目

一. 创建根项目 根项目&#xff08;父项目&#xff09;主要用于依赖管理 一些需要注意的点&#xff1a; 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件&#xff0c;否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...

令牌桶 滑动窗口->限流 分布式信号量->限并发的原理 lua脚本分析介绍

文章目录 前言限流限制并发的实际理解限流令牌桶代码实现结果分析令牌桶lua的模拟实现原理总结&#xff1a; 滑动窗口代码实现结果分析lua脚本原理解析 限并发分布式信号量代码实现结果分析lua脚本实现原理 双注解去实现限流 并发结果分析&#xff1a; 实际业务去理解体会统一注…...

【生成模型】视频生成论文调研

工作清单 上游应用方向&#xff1a;控制、速度、时长、高动态、多主体驱动 类型工作基础模型WAN / WAN-VACE / HunyuanVideo控制条件轨迹控制ATI~镜头控制ReCamMaster~多主体驱动Phantom~音频驱动Let Them Talk: Audio-Driven Multi-Person Conversational Video Generation速…...

TSN交换机正在重构工业网络,PROFINET和EtherCAT会被取代吗?

在工业自动化持续演进的今天&#xff0c;通信网络的角色正变得愈发关键。 2025年6月6日&#xff0c;为期三天的华南国际工业博览会在深圳国际会展中心&#xff08;宝安&#xff09;圆满落幕。作为国内工业通信领域的技术型企业&#xff0c;光路科技&#xff08;Fiberroad&…...

tomcat指定使用的jdk版本

说明 有时候需要对tomcat配置指定的jdk版本号&#xff0c;此时&#xff0c;我们可以通过以下方式进行配置 设置方式 找到tomcat的bin目录中的setclasspath.bat。如果是linux系统则是setclasspath.sh set JAVA_HOMEC:\Program Files\Java\jdk8 set JRE_HOMEC:\Program Files…...

Linux中《基础IO》详细介绍

目录 理解"文件"狭义理解广义理解文件操作的归类认知系统角度文件类别 回顾C文件接口打开文件写文件读文件稍作修改&#xff0c;实现简单cat命令 输出信息到显示器&#xff0c;你有哪些方法stdin & stdout & stderr打开文件的方式 系统⽂件I/O⼀种传递标志位…...