当前位置: 首页 > 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)具有重要的仿生启示。 • 目前的微型飞行器距离自然生物的飞行能力仍有相当差距…...

OpenLayers 可视化之热力图

注&#xff1a;当前使用的是 ol 5.3.0 版本&#xff0c;天地图使用的key请到天地图官网申请&#xff0c;并替换为自己的key 热力图&#xff08;Heatmap&#xff09;又叫热点图&#xff0c;是一种通过特殊高亮显示事物密度分布、变化趋势的数据可视化技术。采用颜色的深浅来显示…...

ffmpeg(四):滤镜命令

FFmpeg 的滤镜命令是用于音视频处理中的强大工具&#xff0c;可以完成剪裁、缩放、加水印、调色、合成、旋转、模糊、叠加字幕等复杂的操作。其核心语法格式一般如下&#xff1a; ffmpeg -i input.mp4 -vf "滤镜参数" output.mp4或者带音频滤镜&#xff1a; ffmpeg…...

Psychopy音频的使用

Psychopy音频的使用 本文主要解决以下问题&#xff1a; 指定音频引擎与设备&#xff1b;播放音频文件 本文所使用的环境&#xff1a; Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音频配置 Psychopy文档链接为Sound - for audio playback — Psy…...

Swagger和OpenApi的前世今生

Swagger与OpenAPI的关系演进是API标准化进程中的重要篇章&#xff0c;二者共同塑造了现代RESTful API的开发范式。 本期就扒一扒其技术演进的关键节点与核心逻辑&#xff1a; &#x1f504; 一、起源与初创期&#xff1a;Swagger的诞生&#xff08;2010-2014&#xff09; 核心…...

大数据学习(132)-HIve数据分析

​​​​&#x1f34b;&#x1f34b;大数据学习&#x1f34b;&#x1f34b; &#x1f525;系列专栏&#xff1a; &#x1f451;哲学语录: 用力所能及&#xff0c;改变世界。 &#x1f496;如果觉得博主的文章还不错的话&#xff0c;请点赞&#x1f44d;收藏⭐️留言&#x1f4…...

云原生玩法三问:构建自定义开发环境

云原生玩法三问&#xff1a;构建自定义开发环境 引言 临时运维一个古董项目&#xff0c;无文档&#xff0c;无环境&#xff0c;无交接人&#xff0c;俗称三无。 运行设备的环境老&#xff0c;本地环境版本高&#xff0c;ssh不过去。正好最近对 腾讯出品的云原生 cnb 感兴趣&…...

基于SpringBoot在线拍卖系统的设计和实现

摘 要 随着社会的发展&#xff0c;社会的各行各业都在利用信息化时代的优势。计算机的优势和普及使得各种信息系统的开发成为必需。 在线拍卖系统&#xff0c;主要的模块包括管理员&#xff1b;首页、个人中心、用户管理、商品类型管理、拍卖商品管理、历史竞拍管理、竞拍订单…...

LLMs 系列实操科普(1)

写在前面&#xff1a; 本期内容我们继续 Andrej Karpathy 的《How I use LLMs》讲座内容&#xff0c;原视频时长 ~130 分钟&#xff0c;以实操演示主流的一些 LLMs 的使用&#xff0c;由于涉及到实操&#xff0c;实际上并不适合以文字整理&#xff0c;但还是决定尽量整理一份笔…...

在Mathematica中实现Newton-Raphson迭代的收敛时间算法(一般三次多项式)

考察一般的三次多项式&#xff0c;以r为参数&#xff1a; p[z_, r_] : z^3 (r - 1) z - r; roots[r_] : z /. Solve[p[z, r] 0, z]&#xff1b; 此多项式的根为&#xff1a; 尽管看起来这个多项式是特殊的&#xff0c;其实一般的三次多项式都是可以通过线性变换化为这个形式…...

三分算法与DeepSeek辅助证明是单峰函数

前置 单峰函数有唯一的最大值&#xff0c;最大值左侧的数值严格单调递增&#xff0c;最大值右侧的数值严格单调递减。 单谷函数有唯一的最小值&#xff0c;最小值左侧的数值严格单调递减&#xff0c;最小值右侧的数值严格单调递增。 三分的本质 三分和二分一样都是通过不断缩…...