C++ Primer笔记——allocator、unique_ptr和release、智能指针与动态数组、阻止拷贝

news2024/9/23 21:21:30

目录

一.P418 unique_ptr和release

二.P426 智能指针与动态数组

(一).unique_ptr

(二).shared_ptr

三.P428 allocator

(一).申请空间

(二).初始化构造

(三).析构

(四).释放空间

(五).相关算法

四.P450 阻止拷贝(类)


一.P418 unique_ptr和release

release函数能够返回一个普通指针指向该空间,并切断unique_ptr与该空间的联系,即放弃对该空间的管理

但是release并不会释放该空间资源,一但没有指针来接收release返回值,那么将造成资源泄漏(指针丢失)。

示例如下:

unique_ptr<int> up(new int);
up.release();//错误,资源泄漏
int* p = up.release();//正确

二.P426 智能指针与动态数组

(一).unique_ptr

unique_ptr自身提供了管理动态数组的删除器delete[],因此使用动态数组时只需要在对象类型后提供一对方括号,表明指针指向的是一个数组。

另外,当使用动态数组后,unique_ptr不再支持*与->,因为此时要将其看做数组使用。应该使用下标运算符来访问

使用方式:

unique_ptr<int[]> up(new int[10]{ 7, 7, 12 });
cout << up[2];//正确
cout << *up;//错误,不再支持解引用

(二).shared_ptr

与unique不同,shared_ptr没有提供管理动态数组的删除器。因此需要我们自定义删除器。

这里我们采用lambda表达式提供定制删除器:

shared_ptr<int> sp(new int[10], [](int* p) {delete[] p;});
//采用lambda传仿函数,使用delete[]释放数组资源

此外,shared_ptr也没有提供下标运算符,如果想要访问数组元素,使用get函数获得普通指针再访问元素

for (size_t i = 0; i < 10; i++) {
    //采用get函数获取普通指针,再按地址访问
	*(sp.get() + i) = 7;
}

三.P428 allocator

allocator定义在<memory>头文件中。

中文上叫做内存池,顾名思义,用于管理动态开辟的内存空间。

与new不同的是,它一般是提前分配了一大块未初始化的空间,使用时再根据所需空间大小进行初始化,其实就是将一块空间资源让使用者自行维护。

分配空间时步骤如下:

1.申请空间

2.初始化构造空间

(一).申请空间

首先定义一个可以申请目标类型空间的allocator类对象a。

再调用allocate函数申请n个所需目标类型对象空间,返回值是指针类型指向开辟的第一个空间。

allocator<string> a;//可以分配string空间的对象
auto p = a.allocate(128);//申请了128个未初始化的string

值得注意的是,此时的空间并不能够直接使用,因为没有进行初始化操作。 

(二).初始化构造

申请空间后,调用construct函数进行空间初始化。

allocator.construct(p, args);

p是目标空间地址的指针,args是该类型的构造函数参数。

auto q = p;//让p一直指向首元素,便于之后释放
a.construct(q++, "hello world");//字符串为"hello world"
a.construct(q++, 10, "hello");//字符串为"hhhhhhhhhh"

使用时直接按指针方式访问即可。 

 释放空间资源时,又分为两步:

1.析构

2.释放空间资源

(三).析构

调用destory函数来完成析构,其接收一个指针对象,自动调用对象的析构函数。如果有多个资源需要释放,那么要一个个调用destory函数

while (q != p) {
	a.destroy(--q);
}

(四).释放空间

最后,调用deallocate函数将已经析构的空间释放即可。

allocator.deallocate(p, n);

参数p是指针,指向释放资源起始位置,n是要释放的该类型资源的数量。

a.deallocate(p, n);//释放n个资源

(五).相关算法

算法含义
uninitialized_copy(b, e, p);将迭代器b到e的内容拷贝到p开始内存中
uninitialized_copy_n(b, n, p);将迭代器b开始n个内容拷贝到p开始内存中
uninitialized_fill(b, e, t);未初始化内存b到e的范围,初始化为t
uninitialized_fill_n(b, n, t);b所指内存开始,创建n个对象初始化为t

代码示例:

vector<int> arr = { 1, 2, 3, 4, 5, 6, 7 };
allocator<int> a;
auto p = a.allocate(128);
//例1
uninitialized_copy(arr.begin(), arr.end(), p);//将数组内容拷贝
//p:1 2 3 4 5 6 7 
//例2
uninitialized_copy_n(arr.begin(), 4, p);
//p:1 2 3 4
//例3
uninitialized_fill(p, p + 5, 1);//给空间创建对象并初始化
//p:1 1 1 1 1
//例4
uninitialized_fill_n(p, 5, 1);
//p:1 1 1 1 1

四.P450 阻止拷贝(类)

方式一:将拷贝构造和拷贝赋值函数删除

class A {
public:
	A() = default;//使用默认构造
	A(const A& a) = delete;//禁掉拷贝构造
	A& operator=(const A& a) = delete;//禁掉赋值
};

方式二:删除析构函数

这里必须指出,因为删除析构函数,栈区对象无法销毁,因此只能在堆区创建对象且无法销毁

class A {
public:
	A() = default;
	~A() = delete;
};

A a;//错误,不能析构
A* b = new A;//正确
delete b;//错误,delete不能调用析构

小编认为严格来讲,这并不是一种阻止拷贝的方式,创建一个无法销毁的对象就意味着内存泄漏的风险。

方式三:将拷贝、赋值设为私有函数

class A {
	A(const A& a);//私有拷贝和赋值
	A& operator=(const A& a);//声明但不定义
public:
	A() = default;
};

注意不要对拷贝和赋值进行定义,这样能阻止类内拷贝的发生(在链接时会报错)。

声明但不定义一个函数是合法的,但是有一个例外,就是派生类对基类虚函数的覆盖,如果只有声明将在多态调用时发生链接错误,无法找到绑定的虚函数的定义。


如有错误,敬请斧正

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

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

相关文章

活动星投票少儿模特大赛网络评选制作一次图文分组投票怎么制作

关于微信投票&#xff0c;我们现在用的最多的就是小程序投票&#xff0c;今天的网络投票&#xff0c;在这里会教大家如何用“活动星投票”小程序来进行投票。我们现在要以“国际车展少儿模特大赛”为主题进行一次投票活动&#xff0c;我们可以在在微信小程序搜索&#xff0c;“…

aws cloudformation 使用模板配置 ecs 蓝绿部署

参考资料 Perform ECS blue/green deployments through CodeDeploy using AWS CloudFormationAWS::CodeDeployBlueGreen 在之前的文章中&#xff0c;使用codepipeline中通过控制台的方式创建了ecs蓝绿部署的demo。实际上可以单独通过codedeploy完成ecs服务的蓝绿部署 参考官…

【ARMv8 SIMD和浮点指令编程】Libyuv I420 转 ARGB 流程分析

Libyuv 可以说是做图形图像相关从业者绕不开的一个常用库&#xff0c;它使用了单指令多数据流提升性能。以 ARM 处理为主线&#xff0c;通过 I420 转 ARGB 流程来分析它是如何流转的。 Libyuv 是一个开源项目&#xff0c;包括 YUV 的缩放和转换功能。 使用邻近、双线性或 box…

QThread、moveToThread用法详述

1.吐槽 QThread类提供了一种平台无关的方法对线程进行管理。但对于QThread类的熟练使用&#xff0c;即使是从事Qt开发多年的程序猿们&#xff0c;往往也会踩雷、入坑。总之&#xff1a;QThread类不好用、如果对该类理解不透&#xff0c;很容易导致程序崩溃。本人强烈建议&#…

(函数介绍)puts()函数

功能介绍 1. puts()函数用来向标准输出设备屏幕输出字符串并换行。 2. 函数的参数就是一个起始的地址&#xff0c;然后就从这个地址开始一直输出字符串&#xff0c;直到碰到\0就停止&#xff0c;然后这个\0是不进行输出的&#xff0c;是不能够算在里面的。与此同时&#xff…

十、字节缓冲流、字符流、转换流、对象操作流、对象序列化流

字节缓冲流 构造方法 字节缓冲流介绍 BufferedOutputStream&#xff1a;该类实现缓冲输出流.通过设置这样的输出流,应用程序可以向底层输出流写入字节,而不必为写入的每个字节导致底层系统的调用BufferedInputStream&#xff1a;创建BufferedInputStream将创建一个内部缓冲区数…

2022年为什么要学习C语言?

为什么学习c语言 为什么学C语言逻辑&#xff1f; 为什么要学习C语言&#xff1f; 学习C语言的主要理由有以下几点&#xff1a; C语言可以作为学习计算机程序设计语言的入门语言&#xff1b; C语言是编写操作系统的首选语言&#xff0c;与计算机硬件打交道时灵巧且高效&…

labelImag安装与使用及构造数据集

在做目标检测任务时&#xff0c;需要进行标注&#xff0c;选择了LabelImg作为标注工具&#xff0c;下面是安装及使用过程。 我们使用Anconda的虚拟环境进行安装&#xff0c;激活环境后&#xff0c;执行&#xff1a; pip install labelimg -i https://pypi.tuna.tsinghua.edu.c…

代码随想录算法训练营第四天 java : 24. 两两交换链表中的节点 ,19.删除链表的倒数第N个节点 ,面试题 02.07. 链表相交,142环形链表II

文章目录Leetcode 24. 两两交换链表中的节点题目链接本题思路需要注意的点AC 代码Leetcode 19.删除链表的倒数第N个节点题目链接需要注意的点AC代码Leetcode面试题 02.07. 链表相交题目链接这个略了Leetcode 142环形链表II题目链接难点:AC代码今日收获**一朵玫瑰正马不停蹄地成…

【Linux】Linux下基本指令(三)

作者&#xff1a;一个喜欢猫咪的的程序员 专栏&#xff1a;《Linux》 喜欢的话&#xff1a;世间因为少年的挺身而出&#xff0c;而更加瑰丽。 ——《人民日报》 目录 1. Linux基本指令&#xff1a;&#xff08;续&#xff09; 1.1zip指令和u…

极智编程 | C++模板函数

欢迎关注我的公众号 [极智视界]&#xff0c;获取我的更多笔记分享 大家好&#xff0c;我是极智视界&#xff0c;本文介绍一下 C模板函数。 模板函数是 C 中一种特殊的函数&#xff0c;它的类型参数列表用尖括号 <> 括起来&#xff0c;放在函数名的后面。使用模板函数&a…

Go 并发

来自 《Go 语言从入门到实战》 的并发章节学习笔记&#xff0c;欢迎阅读斧正&#xff0c;感觉该专栏整体来说对有些后端编程经验的来说比无后端编程经验的人更友好。。 Thread VS Groutine 创建时默认 Stack 大小&#xff1a;前者默认 1M&#xff0c;Groutint 的 Stack 初始化…

C语言可变参数与内存管理

有时&#xff0c;您可能会碰到这样的情况&#xff0c;您希望函数带有可变数量的参数&#xff0c;而不是预定义数量的参数。C 语言为这种情况提供了一个解决方案&#xff0c;它允许您定义一个函数&#xff0c;能根据具体的需求接受可变数量的参数。下面的实例演示了这种函数的定…

LeetCode题解 二叉树(八):404 左叶子之和;513 找树左下角的值;112 路径总和;113 路径总和II

二叉树 404 左叶子之和 easy 左叶子结点也好判断&#xff0c;若某结点属于左结点&#xff0c;且无子树&#xff0c;就是左叶子结点 即也如此&#xff0c;所以如果要判断&#xff0c;必然要从父结点下手&#xff0c;涉及到三层结点的处理 如果要使用递归法&#xff0c;要使用…

(二十三)大白话数据库服务器上的RAID存储架构的电池充放电原理

文章目录 1、RAID卡的缓存2、RAID卡的缓存里的数据会突然丢失怎么办?3、锂电池存在性能衰减问题1、RAID卡的缓存 服务器使用多块磁盘组成的RAID阵列的时候,一般会有一个RAID卡,这个RAID卡是带有一个缓存的,这个缓存不是直接用我们的服务器的主内存的那种模式,他是一种跟内…

网络静态路由综合实验

1.首先分配ip,配置ip和环回 [Huawei]sysname R1 [R1]interface LoopBack 0 [R1-LoopBack0]ip add 192.168.1.33 28 [R1-LoopBack0]q [R1]int l 1 [R1-LoopBack1]ip add 192.168.1.49 28 [R1-LoopBack1]q [R1]int g 0/0/0 [R1-GigabitEthernet0/0/0]ip add 192.168.1.1 30 [R1-…

JVM与Java体系结构

目录 前言 架构师每天都在思考什么&#xff1f; Java vs C Java生态圈 字节码 多语言混合编程 虚拟机与Java虚拟机 虚拟机 Java虚拟机 JVM的位置 JVM整体结构 Java代码执行流程 JVM的架构模型 举例 字节码反编译 总结 栈 JVM生命周期 虚拟机的启动 虚拟机的…

时间从来不语,确回答了所有问题——我的2022年终总结

趁着没阳&#xff0c;趁着电脑还能开机&#xff0c;趁着还能写&#xff0c;赶紧小结过去这一年。没有别的感觉&#xff0c;就是感觉太快&#xff0c;时间太过匆匆.....最大的感触是两个字“变化”&#xff0c;如果非要说四个字是“变化太快”&#xff0c;就如当下的yi情政策&am…

多线程_进阶

文章目录线程通信概念使用方式案例单例模式阻塞式队列线程池常见的锁策略乐观锁 悲观锁CASCAS存在的问题:ABA问题读写锁自旋锁公平锁 非公平锁非公平锁公平锁synchronizedjvm对synchronized的优化:锁升级synchronized的其他优化Lock体系synchronized vs lock独占锁vs共享锁独占…

Arch/Manjaro换源+安装常用的软件+安装显卡驱动

本文将教你&#xff1a;换源安装显卡驱动&#xff0c;安装常用软件例如腾讯会议&#xff0c;QQ&#xff0c;WPS 一起交流Linux知识&#xff0c;欢迎加入Skype群&#xff1a; Join conversationhttps://join.skype.com/q6wrF3d6Usni pacman换清华源 首先安装vim&#xff0c;用来…