C++ —— 智能指针:std::unique_ptr

简介

     智能指针是一种特殊的指针类型,它能够自动管理内存资源,避免常见的内存泄漏和多次释放等。在C++ 11标准中出现了新的智能指针unique_ptr、 shared_ptr、weak_ptr等。

std::unique_ptr

     用于管理动态分配的内存资源,它提供了自动释放内存的功能。与原始指针相比,unique_ptr有更高的安全性和易用性。

     特点: 所有权唯一、自动释放内存、指针语义、禁止拷贝和权限转移、自定义删除器

          所有权唯一:每个unique_ptr实例拥有对其所指向对象的唯一所有权。这意味着在任何时候只有一个unique_ptr可以指向一个特定的对象。

          自动释放内存:当unique_ptr超出作用域或被重新赋值时,它所管理的内存会自动释放。这样就避免了内存泄漏的问题。

          指针语义:使用方式与原始指针相似,可通过指针操作符(->)和解引用操作符(*)来访问所指向对象成员。

          禁止拷贝:unique_ptr禁止拷贝,即不能进行复制构造和赋值操作。这是为了确保独占所有权的特性,防止多个指针同时管理同一个对象的内存。

          权限转移:支持移动构造和移动赋值操作,将所有权转移给新的unique_ptr而旧指针则自动释放置空,无需进行内存拷贝。

          自定义删除器:unique_ptr可通过模板参数来指定一个删除器(deleter)函数对象,用于在释放内存时执行额外的清理操作。

     缺点: 使用裸指针赋值或捕获会很容易非常的乱、导致内存泄露,尽量避免智能指针和普通指针的混合。


     常见成员函数:

常见成员函数:operator*	解引用操作符,用于获取 unique_ptr 所指向对象的引用。operator->	箭头操作符,用于通过 unique_ptr 访问对象的成员函数或成员变量。get			返回指向所管理对象的裸指针。reset		重置 unique_ptr,释放当前所管理的对象并接管新的对象。release		释放对所管理对象的控制权,并返回该指针的裸指针。swap		交换两个 unique_ptr 的内容。


     示例测试:

          基本操作1

#include <iostream>void unique_operate1()
{/******************** 创建 ********************/// 创建方式一,初始化后修改值std::unique_ptr<int> pInt1(new int(10));*pInt1 = 101;// 创建方式二,初始化后修改值std::unique_ptr<int> pInt2 = std::unique_ptr<int>(new int(20));*pInt2 = 102;// 创建方式三,初始化后修改值std::unique_ptr<int> pInt3 = std::make_unique<int>(30);*pInt3 = 103;// 创建多个int指针对象,初始化后修改值std::unique_ptr<int[]> pIntArray(new int[5]{ 10,20,30,40,50 });pIntArray[0] = 1;pIntArray[1] = 2;pIntArray[2] = 3;pIntArray[3] = 4;pIntArray[4] = 5;/*********************************************//******************** 输出地址及值 ********************/std::cout << pInt1 << " " << *pInt1 << " | " << pInt1.get() << " " << *(pInt1.get()) << std::endl;std::cout << pInt1 << " " << *pInt1 << " | " << pInt1.get() << " " << *(pInt1.get()) << std::endl;std::cout << pInt1 << " " << *pInt1 << " | " << pInt1.get() << " " << *(pInt1.get()) << std::endl;/*输出为:000002110F242540 101 | 000002110F242540 101000002110F242540 101 | 000002110F242540 101000002110F242540 101 | 000002110F242540 101*//*********************************************//******************** 权限转移 ********************/std::cout << pInt1 << " " << *pInt1 << std::endl;//std::unique_ptr<int> P1 = pInt1;			// 错误操作std::unique_ptr<int> P1 = std::move(pInt1);	// 正确操作。此时P1接收了pInt1的地址和值,而pInt1则被置空std::cout << P1 << " " << *P1 << std::endl;/*注意:pInt1由于被置空,此时无法使用否则出现异常。输出为:000002303C431670 101000002303C431670 101*//*********************************************/
}int main()
{// 基本操作1unique_operate1();return 0;
}


          基本操作2

#include <iostream>class Operate2
{
public:Operate2(){std::cout << "call Operate2() \t" << this << std::endl;}Operate2(const Operate2 &){std::cout << "call Operate2(const Operate2 &) \t" << this << std::endl;}~Operate2(){std::cout << "call ~Operate2() \t" << this << std::endl;}Operate2* operator +(int v){std::cout << "call operator +  \t" << this << std::endl;Operate2 *tmp = new Operate2;tmp->value = value + v;return tmp;}// 设置value值void setValue(const int &v){ value = v; }// 获取value值int getValue()const { return value; }private:int value = 10;
};void unique_operate2()
{// 进入一次Operate2构造(ptr1)std::unique_ptr<Operate2> ptr1 = std::make_unique<Operate2>();/******************** 成员操作 ********************/// 测试std::cout << "print ptr1 ptr add:" << ptr1 << std::endl << std::endl;// 测试 ->std::cout << "print ptr2 - value is:" << ptr1->getValue() << std::endl;ptr1->setValue(20);std::cout << "print ptr2 - value is:" << ptr1->getValue() << std::endl << std::endl;// 测试 get	:返回指向所管理对象的裸指针Operate2 *tOperate2Ptr = ptr1.get();std::cout << "tOperate2Ptr - value is:" << ptr1->getValue() << std::endl << std::endl;/*测试 reset :该方法可让unique_ptr解除对原始内存管理,也可初始化一个独占的智能指针reset()				解除对原始内存的管理reset(new xxx())	重新指定智能指针管理的原始内存*/ptr1.reset(new Operate2());					// 新创建的进入一次构造,然后之前的对象进入一次析构std::cout << "new print ptr2 - value is:" << ptr1->getValue() << std::endl << std::endl;// 测试 release	:释放对所管理对象的控制权,并返回该指针的裸指针Operate2 *ttOperate2Ptr = ptr1.release();	// ptr1被置空if (ttOperate2Ptr) { delete ttOperate2Ptr; }ttOperate2Ptr = nullptr;std::cout << std::endl;// 测试 swap	:交换两个unique_ptr的内容std::unique_ptr<Operate2> Operate2_1 = std::make_unique<Operate2>(); Operate2_1->setValue(6);std::unique_ptr<Operate2> Operate2_2 = std::make_unique<Operate2>(); Operate2_2->setValue(9);std::cout << "Operate2_1:" << Operate2_1->getValue() << " Operate2_2:" << Operate2_1->getValue() << std::endl;Operate2_1.swap(Operate2_2);std::cout << "Operate2_1:" << Operate2_1->getValue() << " Operate2_2:" << Operate2_1->getValue() << std::endl;/*********************************************/// 函数结束,进入一次Operate2析构(ptr1)
}int main()
{// 基本操作2unique_operate2();/*输出为:call Operate2()         0000029218F50140print ptr1 ptr add:0000029218F50140print ptr2 - value is:10print ptr2 - value is:20tOperate2Ptr - value is:20call Operate2()         0000029218F501C0call ~Operate2()        0000029218F50140new print ptr2 - value is:10call ~Operate2()        0000029218F501C0call Operate2()         0000029218F50140call Operate2()         0000029218F501C0Operate2_1:6 Operate2_2:6Operate2_1:9 Operate2_2:9call ~Operate2()        0000029218F50140call ~Operate2()        0000029218F501C0*/return 0;
}


          基本操作3

#include <iostream>class TestClass
{
public:TestClass(){std::cout << "call TestClass() \t" << this << std::endl;}TestClass(const TestClass &){std::cout << "call TestClass(const TestClass &) \t" << this << std::endl;}~TestClass(){std::cout << "call ~TestClass() \t" << this << std::endl;}TestClass* operator +(int v){std::cout << "call TestClass +  \t" << this << std::endl;TestClass *tmp = new TestClass;tmp->value = value + v;return tmp;}// 设置value值void setValue(const int &v){ value = v; }// 获取value值int getValue()const { return value; }private:int value = 100;
};std::unique_ptr<TestClass> changeValue_add10(std::unique_ptr<TestClass> tcPtr)
{tcPtr->setValue(tcPtr->getValue() + 10);return tcPtr;
}void unique_operate3()
{std::unique_ptr<TestClass> tcPtr1 = std::make_unique<TestClass>();if (tcPtr1) { std::cout << "11111:\t" << "ptr:" << tcPtr1 << " *ptr:" << tcPtr1->getValue() << std::endl; }//changeValue_add10(stcPtr1);	// 错误:由于unique_ptr不能拷贝,故不得作为形参进行拷贝给实参std::unique_ptr<TestClass> tcPtr2 = changeValue_add10(std::move(tcPtr1));if (tcPtr2) { std::cout << "22222:\t" << "ptr:" << tcPtr2 << " *ptr:" << tcPtr2->getValue() << std::endl; }
}int main()
{// 基本操作3unique_operate3();/*输出为:call TestClass()        000001F354580A6011111:  ptr:000001F354580A60 *ptr:10022222:  ptr:000001F354580A60 *ptr:110call ~TestClass()       000001F354580A60*/return 0;
}

关注

笔者 - jxd

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/668965.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CVE-2024-23897:Jenkins文件读取漏洞复现分析 [附POC]

文章目录 CVE-2024-23897 Jenkins文件读取漏洞复现分析 [附POC]0x01 前言0x02 漏洞描述0x03 影响版本0x04 漏洞环境搭建0x05 漏洞复现1.访问漏洞环境2.执行POC3.复现0x06 漏洞分析1.获取源码2.解压并使用IDEA打开0x07 修复建议0x08 总结

linux系统haproxy负载均衡器使用keepalived做高可用

haproxy负载均衡器做高可用 haproxykeepalived haproxykeepalived 两台负载均衡器都安装 yum -y install haproxyvim /etc/haproxy/haproxy.cfggloballog 127.0.0.1 local2 infopidfile /var/run/haproxy.pidmaxconn 4000 #优先级低user haproxygrou…

【echarts】动态滚动趋势图,解决坐标轴数据太多遮挡覆盖问题

写在前面 业务场景x轴的文字太多&#xff0c;会出现遮挡问题&#xff0c;想到文字倾斜展示&#xff0c;页面不美观&#xff0c;于是想到使用滚动条优化趋势图。 <template><div id"storeDown" style"height: 400px;width:100%"/> </temp…

基于SpringBoot的后端导出Excel文件

后端导出Excel&#xff0c;前端下载。 系列文章指路&#x1f449; 系列文章-基于SpringBoot3创建项目并配置常用的工具和一些常用的类 文章目录 后端导出Excel引入依赖写入响应 前端下载后端导出失败和成功返回的内容类型不同&#xff0c;因此需要分别判断。 工具类ServletUti…

GLIP:零样本学习 + 目标检测 + 视觉语言大模型

GLIP 核心思想GLIP 对比 BLIP、BLIP-2、CLIP 主要问题: 如何构建一个能够在不同任务和领域中以零样本或少样本方式无缝迁移的预训练模型&#xff1f;统一的短语定位损失语言意识的深度融合预训练数据类型的结合语义丰富数据的扩展零样本和少样本迁移学习 效果 论文&#xff1a;…

docker核心技术

一. 从系统架构谈起 传统分层架构 vs 微服务 微服务改造 分离微服务的方法建议: 审视并发现可以分离的业务逻辑业务逻辑,在对业务领域不是特别熟悉的时候,按照部门职能进行划分,例如账号、财务等寻找天生隔离的代码模块,可以借助于静态代码分析工具如果可以闭环的解决一…

SQL Server之DML触发器

一、如何创建一个触发器呢 触发器的定义语言如下&#xff1a; CREATE [ OR ALTER ] TRIGGER trigger_nameon {table_name | view_name}{for | After | Instead of }[ insert, update,delete ]assql_statement从这个定义语言我们可以知道如下信息&#xff1a; trigger_name&…

从领域外到领域内:LLM在Text-to-SQL任务中的演进之路

导语 本文介绍了ODIS框架&#xff0c;这是一种新颖的Text-to-SQL方法&#xff0c;它结合了领域外示例和合成生成的领域内示例&#xff0c;以提升大型语言模型在In-context Learning中的性能。 标题&#xff1a;Selective Demonstrations for Cross-domain Text-to-SQL会议&am…

计算机组成原理 — 存储器(1)

存储器 大家好呀&#xff01;我是小笙&#xff0c;由于存储器这部分章节内容较多&#xff0c;我分成二部分进行总结&#xff0c;以下是第一部分&#xff0c;希望内容对你有所帮助&#xff01; 概述 存储器是计算机系统中的记忆设备&#xff0c;用来存放程序和数据 存储器分…

vue3 mathjax 数学公式

安装 pnpm install mathjax 新建文件/util/mathjax.js window.MathJax {tex: {inlineMath: [["$", "$"],["\\(", "\\)"],], // 行内公式选择符displayMath: [["$$", "$$"],["\\[", "\\]"…

【大数据面试题】002 Flink 如何实现 Exactly-Once 语义

一步一个脚印&#xff0c;一天一道大数据面试题。 在流式大数据处理框架中&#xff0c;Exactly-Once 语义对于确保每条数据精确地只被消费一次&#xff08;避免重复读取和丢失读取&#xff09;非常重要。下面将介绍 Flink 是如何实现 Exactly-Once 语义的。 尽管在程序正常运…

UE4运用C++和框架开发坦克大战教程笔记(十七)(第51~54集)

UE4运用C和框架开发坦克大战教程笔记&#xff08;十七&#xff09;&#xff08;第51~54集&#xff09; 51. UI 框架介绍UE4 使用 UI 所面临的问题以及解决思路关于即将编写的 UI 框架的思维导图 52. 管理类与面板类53. 预加载与直接加载54. UI 首次进入界面 51. UI 框架介绍 U…

《合成孔径雷达成像算法与实现》Figure6.4

clc clear close all参数设置 距离向参数设置 R_eta_c 20e3; % 景中心斜距 Tr 2.5e-6; % 发射脉冲时宽 Kr 20e12; % 距离向调频率 alpha_os_r 1.2; % 距离过采样率 Nrg 320; % 距离线采样数 距离向…

CSS布局

CSS布局 1. 版心 在 PC 端网页中&#xff0c;一般都会有一个固定宽度且水平居中的盒子&#xff0c;来显示网页的主要内容&#xff0c;这是网页的版心。版心的宽度一般是 960 ~ 1200 像素之间。版心可以是一个&#xff0c;也可以是多个。 2. 常用布局名词 3. 重置默认样式 很…

C#验证字符串的长度,用正则表达式 vs 字符数组长度或字符串的长度

目录 一、使用的方法 1.使用正则表达式 2.通过计算字符串的长度验证 二、实例 1.源码 2.生成效果 一、使用的方法 1.使用正则表达式 使用正则表达式可以判断和限制用户输入的字符串长度。 比如验证用户密码不得少于8为&#xff0c;匹配的正则表达式"^.{8,}$"…

LeetCode977 有序数组的平方

暴力解法是平方之后排序复杂度是nnlogn 优化解法是双指针i&#xff0c;j&#xff0c;i放数组首元素位置&#xff0c;j放数组末尾&#xff0c;每次比较i和j位置的数组元素大小&#xff0c;然后挑一个大的放在新的数组元素的指定末尾位置上。 当原始数组nums第一个元素大于零时&a…

AIGC专题:AIGC教育行业全景报告

今天分享的是AI GC系列深度研究报告&#xff1a;《AIGC专题&#xff1a;AIGC教育行业全景报告》。 &#xff08;报告出品方&#xff1a;量子位智库&#xff09; 报告共计&#xff1a;31页 生成式AI快速落地教育&#xff0c;技术推动教育理念实施 生成式AI将我们带入AI2.0时代…

数据类型完整版

第三章 数据类型 3.1 Key操作 3.1.1 相关命令 序号命令语法描述1DEL key该命令用于在 key 存在时删除 key2DUMP key序列化给定 key &#xff0c;并返回被序列化的值3EXISTS key检查给定 key 是否存在&#xff0c;存在返回1&#xff0c;否则返回04EXPIRE key seconds为给定 k…

springboot(ssm船舶监造系统 船只生产管理系统Java系统

springboot(ssm船舶监造系统 船只生产管理系统Java系统 开发语言&#xff1a;Java 框架&#xff1a;springboot&#xff08;可改ssm&#xff09; vue JDK版本&#xff1a;JDK1.8&#xff08;或11&#xff09; 服务器&#xff1a;tomcat 数据库&#xff1a;mysql 5.7&#…

MacOS系统电脑远程桌面控制windows系统电脑【内网穿透】

最近&#xff0c;我发现了一个超级强大的人工智能学习网站。它以通俗易懂的方式呈现复杂的概念&#xff0c;而且内容风趣幽默。我觉得它对大家可能会有所帮助&#xff0c;所以我在此分享。点击这里跳转到网站。 文章目录 1. 测试本地局域网内远程控制1.1 Windows打开远程桌面1…