C++ —— 智能指针 unique_ptr (上)
C++ —— 智能指针 unique_ptr (上)
- 普通指针的不足
- 普通指针的释放
- 智能指针
- 智能指针 unique_ptr
- 智能指针初始化
- 错误用法
- get()方法返回裸指针
- 智能指针不支持指针的运算(+、-、++、- -)
普通指针的不足
new和new []的内存需要用delete和delete []释放(堆区的内存一定要手工释放,否则会发生内存的泄露);- 程序员主观上的失误,忘记或漏掉释放;
- 不确定何时释放。
普通指针的释放
类内的指针,在析构函数中释放;- 堆区的内存是
C++内置数据类型,没有析构函数,只能delete释放; new出来的类,还是得用delete释放。
智能指针
智能指针的目的:解决资源释放的问题。
智能指针使用步骤:
- 智能指针是类模板,在栈上创建智能指针对象;
- 把普通指针交给智能指针对象;
- 智能指针对象过期时,调用析构函数释放普通指针的内存。
C++11标准的智能指针类型:unique_ptr、shared_ptr、weak_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 (上) 普通指针的不足普通指针的释放智能指针智能指针 unique_ptr智能指针初始化错误用法get()方法返回裸指针智能指针不支持指针的运算(、-、、- -) 普通指针的不足 new和new [] 的内存需要用delete和…...
技术 · 创作 · 生活 | 我的 2024 全面复盘
目录 🌟2024年度总结:回顾、成长与突破🌟🚀 一、技术成长与突破 🚀🔗 1. 深入区块链与智能合约🔍 2. 探索新兴技术 ✍️ 二、创作与博客历程 ✍️📖 1. 内容创作的演变🏆…...
表的增删改查(MySQL)
1. 表的增删改查 CRUD : Create(创建), Retrieve(读取),Update(更新),Delete(删除) 1.1 Create 语法: INSERT [INTO] table_name [(column [, column] ...)] VALUES (value_list) [, (value_list)] ...value_list:…...
【设计模式】JAVA 策略 工厂 模式 彻底告别switch if 等
【设计模式】JAVA 策略 工厂 模式 彻底告别switch if 等 目录 【设计模式】JAVA 策略 工厂 模式 彻底告别switch if 等 优势 适用场景 项目结构 关键代码 优势 消除 switch:将分支逻辑分散到独立的策略类中。 开闭原则:新增类型只需添加新的 TypeHa…...
基于Springboot用axiospost请求接收字符串参数为null的解决方案
问题 今天在用前端 post 请求后端时发现,由于是以 Json对象的形式传输的,后端用两个字符串形参无法获取到对应的参数值 前端代码如下: axios.post(http://localhost:8083/test/postParams,{a: 1, b:2} ,{Content-Type: application/jso…...
最长递增——蓝桥杯
1.题目描述 在数列 a1,a2,⋯,an 中,如果ai<ai1<ai2<⋯<aj,则称 ai 至 aj 为一段递增序列,长度为 j−i1。 定一个数列,请问数列中最长的递增序列有多长。 输入描述 输入的第一行包含一个整数 n。…...
【MFC】C++所有控件随窗口大小全自动等比例缩放源码(控件内字体、列宽等未调整) 20250124
MFC界面全自动等比例缩放 1.在初始化里 枚举每个控件记录所有控件rect 2.在OnSize里,根据当前窗口和之前保存的窗口的宽高求比例x、y 3.枚举每个控件,根据比例x、y调整控件上下左右,并移动到新rect struct ControlInfo {CWnd* pControl;CRect original…...
C#标准Mes接口框架(持续更新)
前言 由于近期我做了好几个客户的接入工厂Mes系统的需求。但是每个客户的Mes都有不同程度的定制需求,原有的代码复用难度其实很大。所以打算将整个接入Mes系统的框架单独拿出来作为一个项目使用,同时因为不同的设备接入同一个Mes系统,所以代…...
【Uniapp-Vue3】动态设置页面导航条的样式
1. 动态修改导航条标题 uni.setNavigationBarTitle({ title:"标题名称" }) 点击修改以后顶部导航栏的标题会从“主页”变为“动态标题” 2. 动态修改导航条颜色 uni.setNavigationBarColor({ backgroundColor:"颜色" }) 3. 动态添加导航加载动画 // 添加加…...
SQL 递归 ---- WITH RECURSIVE 的用法
SQL 递归 ---- WITH RECURSIVE 的用法 开发中遇到了一个需求,传递一个父类id,获取父类的信息,同时获取其所有子类的信息。 首先想到的是通过程序中去递归查,但这种方法着实孬了一点,于是想,sql能不能递归查…...
期权帮|如何利用股指期货进行对冲套利?
锦鲤三三每日分享期权知识,帮助期权新手及时有效地掌握即市趋势与新资讯! 如何利用股指期货进行对冲套利? 对冲就是通过股指期货来平衡投资组合的风险。它分为正向与反向两种策略: (1)正向对冲ÿ…...
INCOSE需求编写指南-第1部分:介绍
第1部分:介绍Section 1: Introduction 1.1 目的和范围 Purpose and Scope 本指南专门介绍如何在系统工程背景下以文本形式表达需求和要求陈述。其目的是将现有标准(如 ISO/IEC/IEEE 29148)中的建议以及作者、主要贡献者和审稿员的最佳实践结…...
FFPlay命令全集合
FFPlay是以FFmpeg框架为基础,外加渲染音视频的库libSDL构建的媒体文件播放器。 ffplay工具下载并播放视频,可以辅助卡看流信息。 官网下载地址:http://ffmpeg.org/download.html#build-windows 下载build好的exe程序: 此处下载…...
Mono里运行C#脚本34—内部函数调用的过程
本文来分析Mono运行脚本时,会调用一些C实现的函数代码。 而这个过程又是怎么样实现的呢? 比如前面分析的脚本: IL_0000: call string class MonoEmbed::gimme() 在这里会调用C函数实现的MonoEmbed::gimme()函数。 而这个函数是在C程序内部实现,通过下面的代码来注册到运行…...
rust feature h和 workspace相关知识 (十一)
feature 相关作用和描述 在 Rust 中,features(特性) 是一种控制可选功能和依赖的机制。它允许你在编译时根据不同的需求启用或禁用某些功能,优化构建,甚至改变代码的行为。Rust 的特性使得你可以轻松地为库提供不同的…...
-bash: ./uninstall.command: /bin/sh^M: 坏的解释器: 没有那个文件或目录
终端报错: -bash: ./uninstall.command: /bin/sh^M: 坏的解释器: 没有那个文件或目录原因:由于文件行尾符不匹配导致的。当脚本文件在Windows环境中创建或编辑后,行尾符为CRLF(即回车和换行,\r\n)…...
【Redis】Redis入门以及什么是分布式系统{Redis引入+分布式系统介绍}
文章目录 介绍redis的引入 分布式系统单机架构应用服务和数据库服务分离【负载均衡】引入更多的应用服务器节点 单机架构 分布式是什么 数据库分离和负载均衡 理解负载均衡 数据库读写分离 引入缓存 数据库分库分表 引入微服务 介绍 The open source, in-memory data store us…...
C#高级:常用的扩展方法大全
1.String public static class StringExtensions {/// <summary>/// 字符串转List(中逗 英逗分隔)/// </summary>public static List<string> SplitCommaToList(this string data){if (string.IsNullOrEmpty(data)){return new List&…...
Consul持久化配置报错1067---consul_start
报错都是文件写的有问题或者格式问题,直接复制我的这个改改地址就行 先创建文本文件consul_start.txt--->再复制代码保存---->再把.txt改成.bat 持久化存储的地址在:mydata 注:D:\consul\consul_1.20.2_windows_386改成自己consul的…...
「 机器人 」扑翼飞行器控制策略浅谈
1. 研究背景 • 自然界中的蜂鸟以极高的机动能力著称,能够在短至0.2秒内完成如急转弯、快速加速、倒飞、躲避威胁等极限机动。这种表现对微型飞行器(Flapping Wing Micro Air Vehicles, FWMAVs)具有重要的仿生启示。 • 目前的微型飞行器距离自然生物的飞行能力仍有相当差距…...
内存分配函数malloc kmalloc vmalloc
内存分配函数malloc kmalloc vmalloc malloc实现步骤: 1)请求大小调整:首先,malloc 需要调整用户请求的大小,以适应内部数据结构(例如,可能需要存储额外的元数据)。通常,这包括对齐调整,确保分配的内存地址满足特定硬件要求(如对齐到8字节或16字节边界)。 2)空闲…...
Python爬虫实战:研究feedparser库相关技术
1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的信息资源。RSS(Really Simple Syndication)作为一种标准化的信息聚合技术,被广泛用于网站内容的发布和订阅。通过 RSS,用户可以方便地获取网站更新的内容,而无需频繁访问各个网站。 然而,互联网…...
CentOS下的分布式内存计算Spark环境部署
一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架,相比 MapReduce 具有以下核心优势: 内存计算:数据可常驻内存,迭代计算性能提升 10-100 倍(文档段落:3-79…...
Java 加密常用的各种算法及其选择
在数字化时代,数据安全至关重要,Java 作为广泛应用的编程语言,提供了丰富的加密算法来保障数据的保密性、完整性和真实性。了解这些常用加密算法及其适用场景,有助于开发者在不同的业务需求中做出正确的选择。 一、对称加密算法…...
unix/linux,sudo,其发展历程详细时间线、由来、历史背景
sudo 的诞生和演化,本身就是一部 Unix/Linux 系统管理哲学变迁的微缩史。来,让我们拨开时间的迷雾,一同探寻 sudo 那波澜壮阔(也颇为实用主义)的发展历程。 历史背景:su的时代与困境 ( 20 世纪 70 年代 - 80 年代初) 在 sudo 出现之前,Unix 系统管理员和需要特权操作的…...
Spring AI 入门:Java 开发者的生成式 AI 实践之路
一、Spring AI 简介 在人工智能技术快速迭代的今天,Spring AI 作为 Spring 生态系统的新生力量,正在成为 Java 开发者拥抱生成式 AI 的最佳选择。该框架通过模块化设计实现了与主流 AI 服务(如 OpenAI、Anthropic)的无缝对接&…...
Redis数据倾斜问题解决
Redis 数据倾斜问题解析与解决方案 什么是 Redis 数据倾斜 Redis 数据倾斜指的是在 Redis 集群中,部分节点存储的数据量或访问量远高于其他节点,导致这些节点负载过高,影响整体性能。 数据倾斜的主要表现 部分节点内存使用率远高于其他节…...
Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...
GC1808高性能24位立体声音频ADC芯片解析
1. 芯片概述 GC1808是一款24位立体声音频模数转换器(ADC),支持8kHz~96kHz采样率,集成Δ-Σ调制器、数字抗混叠滤波器和高通滤波器,适用于高保真音频采集场景。 2. 核心特性 高精度:24位分辨率,…...
C# 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...
