C++11新特性(2) ——动态内存和智能指针从入门到入坑

动态内存与智能指针

动态内存的使用十分容易出现问题(内存泄漏/非法内存),而智能指针能更安全、容易的使用动态内存,因为他负责自动释放所指向的对象,并且在出现异常时,也会自动释放。
两种智能指针,区别是管理底层指针的方式:
shared_ptr :允许多指针指向同一个对象
unique_ptr独占所指向的对象
weak_ptr:弱引用,指向shared_ptr所管理的对象。
auto_ptr:和weak相比,主要差异是支持拷贝构造与赋值操作

shared_ptr p1; ///< 指向string
shared_ptr <list> p2; ///< 指向int的list
默认初始化的智能指针中保存一个空指针,使用方法与指针类似

shared_ptr和unique_ptr共有操作

shared_ptr sp unique_ptr up 默认初始化空智能指针
使用智能指针:p *p p->mem 与指针类似
p.get() 返回p中保存的指针。(若智能指针释放,则返回指针所指向对象也释放了)
swap(p,q) p.swap(q)交换p和q的指针

shared_ptr独有操作

make_shared(args) 返回shared_ptr,指向一个动态分配,以args初始化类型为T的对象
shared_ptrp(q)p是q的拷贝,此操作会递增q中计数器
shared_ptrp(q,d)p是q的拷贝,此操作会递增q中计数器,d用于代替delete函数
p=q递减p引用计数,递增q引用计数,引用为0时释放内存
p.use_count() 返回和p共享对象的智能指针数量
p.unique 若count 为1 返回true

关于new分配内存的操作
shared_ptr p(q) q指向new分配的T*类型数据,p管理该对象
shared_ptr p(u) 从unique_ptr对象u接管所有权,u置为空
shared_ptr p(q,d) p接管new出来的q,并且使用d函数代替delete函数
p.reset()、p.reset(q)、p.reset(q,d) 若有d,则使用d代替delete,若有q,则令p指向q,若都无,则代表释放此对象。

unique_ptr操作


/// release 放弃控制权,返回指针并置为空(不会释放之前指向的对象)
/// reset(q)   释放指向的对象,并指向新对象q,若为空,则只是释放操作

int main(int argc, char **argv)
{unique_ptr<int> uni1(new int(1));unique_ptr<int> uni2(uni1.release());   /// uni1放弃对指针的控制权,返回指针,并将uni1置为空unique_ptr<int> uni3(new int(3));uni1.reset(new int(4));                 /// 释放uni1指向的对象,并让uni1指向新的对象uni1.reset(nullptr);                    /// 释放uni1指向的对象,并让uni1指向null         cout << uni1.get() <<endl;if (uni1.get() != NULL){cout << *uni1 <<endl;}cout << uni2.get() <<endl;if (uni2.get() != NULL){cout << *uni2 <<endl;}
}

智能指针使用

智能指针管理对象原理每个shared_ptr都有一个关联的计数器,称为引用计数,当引用计数为0时,会自动释放所管理的对象

make_shared初始化

使用动态内存最安全的方法就是使用make_shared
shared_ptr p = make_shared(42); /// 指向int的shared_ptr
shared_ptr p = make_shared(42); ///指向string “9999999999”
auto p = make_shared<vector>
p = q; p内存自动释放 q引用递增
/// p的作用域结束时,调用析构函数,指向的内存自动释放,而return p时,引用计数发生了递增。

使用类实现数据共享

智能指针加容器


initializer_list v 代表是初始化列表传递

shared_ptr 和 new 结合使用

shared_ptr p = new int(40); /// 错误。不能将普通指针隐式初始化为智能指针
shared_ptr p(new int (42)); /// 正确,直接初始化
当shared_ptr绑定到一个普通指针时,内存管理的责任将交给shared_ptr,不应该再使用内置指针访问被管理的内存,因为此时内置指针访问时,智能指针是不知道的。所以建议在定义智能指针时直接初始化动态内存。

智能指针的异常兜底

void func()
{int *p = new int(42);/// 若此时抛出异常,且未进行捕获操作,则发生内存泄漏delete p;
}void func()
{shared_ptr <int> sp(new int (42));/// 抛出异常且未捕获/// 函数结束时自动释放内存
}

unique_ptr

与shared_ptr的区别是,它是独占式,并且没有make_shared操作,需要绑定到new 返回的指针上。

unique_ptr p1; /// 正确,指向double
unique_ptr p2(new int(42)) ///正确,指向值为42的int

因为unique_ptr是独占式,所以不支持普通的拷贝或赋值,但有例外,可以拷贝或赋值一个将要被销毁的unique_ptr,最常见的就是函数中返回一个unique_ptr。

重写unique_ptr的删除器代替delete

decltype关键字

auto和decltype都用于自动类型推导,但用法有差别。
auto valname = value;
decltype(exp) varname = value;
decltype(exp) varname;
///auto根据右边的初始值value,推导变量类型,而decltype根据exp表达式,推导出变量类型
///,auto必须要初始化
如果 exp 是一个表达式,或者是一个单独的变量,那么 decltype(exp) 的类型就和 exp 一致。
如果 exp 是函数调用,那么 decltype(exp) 的类型就和函数返回值的类型一致。所以不能返回void类型
如果 exp 是一个左值,或者被括号( )包围,那么 decltype(exp) 的类型就是 exp 的引用;假设 exp 的类型为 T,那么 decltype(exp) 的类型就是 T&。
如果exp是函数类型,那么返回也是函数类型。加上*后变为函数指针

weak_ptr

弱引用智能指针:不控制所指向对象的生存周期,指向由shared_ptr管理的对象,使用前必须调用检查对象是否还存在。

weak_ptr绑定到shared_ptr之后,不会改变它的引用计数,实现“弱”共享对象。

auto p = make_shared(42);
if (shared_ptr np = wp.lock()) { ///检查对象是否还存在,存在才能访问,保证安全
weak_ptr wp§; ///弱共享p,不改变p的引用计数。
}

注意事项

1、get 用来将指针的访问权限传递给代码,仅限于某些不能传递智能指针的场合。因为get到指针地址后,如果用该普通指针初始化智能指针,并不会增加引用计数,之后可能发生double free。(不能用于初始化或reset另一个智能指针,不能delete)
2、不使用相同的内置指针初始化(或reset)多个智能指针。(多个智能指针管理同一片内存,并且互不感知)
3、如果智能指针管理的资源,不是new出来的内存,需要传递一个删除器代替delete操作
4、智能指针的内存泄漏问题:当两个shared_ptr互相指向,则会造成循环引用,引用计数始终不为0,导致内存泄漏。解决办法:将其中一个share_ptr改为弱引用指针weak_ptr,弱引用指针不修改引用计数的值,从而不会对对象的内存进行管理。并且它可以检测到所管理对象是否已释放,避免非法访问
5、引用计数并不是原子操作,第一步复制内容的ptr指针,第二步引用计数+1,所以多线程需要加锁

动态数组

.。。。。。。。。。。。。。待完善

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

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

相关文章

《springcloud alibaba》 四 seata安装以及使用

目录 准备调整db配置准备创建数据库 seata配置nacos配置confi.txt下载向nacos推送配置的脚本 启动seata新建项目order-seata项目 订单项目数据库脚本pom.xmlapplication.yml启动类实体类dao类service类controller类feign类mapper类 stock-seata 库存项目数据库脚本pom.xmlappli…

STM32学习和实践笔记(5):时钟树

STM32一共有4个时钟源。外部时钟高低速各一个&#xff0c;内部时钟高低速各一个。 外部高速时钟是&#xff1a;4-16MHZ的HSE OSC。HS表示高速high speed. E表示外部的external。开发板该处安装的8M晶振。 外部低速时钟是&#xff1a;32.768KHz的LSI OSC。LS表示高速low speed…

【IP层的校验和与UDP的校验和】+【FPGA实现】

IP头校验和 IP头校验和是一种错误检测机制&#xff0c;用于在互联网协议&#xff08;IP&#xff09;中保证IP头的数据完整性。 当一个IP数据包从源主机发送到目的主机时&#xff0c;它经过许多路由器和交换机&#xff0c;校验和可以帮助这些中间设备检查数据包在传输过程中是…

为说阿拉伯语的国家进行游戏本地化

阿拉伯语是由超过4亿人使用的语言&#xff0c;并且是二十多个国家的官方语言。进入这些国家的市场并非易事——虽然他们共享一种通用语言&#xff0c;但每个国家都有自己独特的文化&#xff0c;有自己的禁忌和对审查的处理方式。这就是为什么视频游戏公司长期以来都远离阿拉伯语…

Qt QML的插件(Qt Quick 2 Extension Plugin)方法

Qt Quick的插件方法 序言环境前置注意概念——Qt Quick插件的相关知识插件里的qml文件模块名的相关知识模块名本身注意事项模块名版本注意事项 以示例来说明创建插件qmltypes的生成qmltypes的可能性失效 插件的编码注意1、插件模块版本控制2、pro里的注意 调用插件插件信息输入…

华为手机 鸿蒙系统 或者安卓系统的百度网盘下载的文件保存在手机什么位置如何查看

华为手机 鸿蒙系统 或者安卓系统的百度网盘下载的文件保存在手机什么位置如何查看 连接电脑后一般在这里位置 计算机\Mate 20 Pro (UD)\内部存储\Download\BaiduNetdisk 也就是用usb&#xff08;数据线&#xff0c;不是充电线&#xff0c;要四心的 )连接手机后&#xff0c;打…

计算机网络——40各个层次的安全性

各个层次的安全性 安全电子邮件 Alice需要发送机密的报文m给Bob Alice 产生随机的对称秘钥&#xff0c; K s K_s Ks​使用 K s K_s Ks​对报文进行加密&#xff08;为了效率&#xff09;对 K s K_s Ks​使用Bob的公钥进行加密发送 K s ( m ) K_s(m) Ks​(m)和 K B ( K S ) K…

设计模式:生活中的责任链模式

责任链模式可以用一个日常生活中的接力赛来类比。在接力赛中&#xff0c;每个跑步者负责赛道的一段距离&#xff0c;然后将接力棒传递给下一个跑步者&#xff0c;直到最后一个跑步者完成比赛。每个跑步者都有机会跑自己的那一段&#xff0c;但如果他跑不了&#xff0c;他需要将…

uniapp如何配置后使用uni.chooseLocation等地图位置api

在uniapp中想要使用uni.getLocation、uni.chooseLocation ……api的时候我们需要在小程序就开启配置&#xff0c;不然无法使用。 第一步&#xff1a;首先找到manifest.json 第二步&#xff1a;点击源码视图 第三步&#xff1a;在 mp-weixin 加入下面代码 "permission&…

Paper Digest | GPT-RE:基于大语言模型针对关系抽取的上下文学习

持续分享 SPG 及 SPG LLM 双驱架构应用相关进展 1、动机 在很多自然语言处理任务中&#xff0c;上下文学习的性能已经媲美甚至超过了全资源微调的方法。但是&#xff0c;其在关系抽取任务上的性能却不尽如人意。以 GPT-3 为例&#xff0c;一些基于 GPT-3 的上下文学习抽取方…

DXP学习002-PCB编辑器的环境参数及电路板参数相关设置

目录 一&#xff0c;dxp的pcb编辑器环境 1&#xff0c;创建新的PCB设计文档 2&#xff0c;PCB编辑器界面 1&#xff09;布线工具栏 2&#xff09;公用工具栏 3&#xff09;层标签栏 ​编辑 3&#xff0c;PCB设计面板 1&#xff09;打开pcb设计面板 4&#xff0c;PCB观…

【HTML】简单制作一个分形动画

目录 前言 开始 HTML部分 效果图 ​编辑​编辑​编辑​编辑总结 前言 无需多言&#xff0c;本文将详细介绍一段代码&#xff0c;具体内容如下&#xff1a; 开始 首先新建文件夹&#xff0c;创建一个文本文档&#xff0c;其中HTML的文件名改为[index.html]&a…

JavaEE初阶之单例模式详解

目录 题外话 正题 单例模式 概念 优点 缺点 饿汉式单例模式 代码及详解 懒汉式单例模式 代码及详解 小结 题外话 昨天爬山去了,回来吃了个烧烤有点累,昨天旷了一天,每周稳定发个五篇文章是没什么太大问题的 正题 单例模式 概念 是一种常见的软件设计模式,确保一个类…

nginx 配置访问地址和解决跨域问题(反向代理)

1、配置访问地址&#xff08;通过ip访问&#xff09; //配置ip访问地址 location ^~/auditApp{alias /usr/local/front-apps/cbd/auditApp;index index.html;if (!-e $request_filename) {rewrite ^/(.*) /auditApp/index.html last;break;}} 2、解决跨域问题&…

电商技术揭秘十四:大数据平台的选择与构建

相关系列文章 电商技术揭秘一&#xff1a;电商架构设计与核心技术 电商技术揭秘二&#xff1a;电商平台推荐系统的实现与优化 电商技术揭秘三&#xff1a;电商平台的支付与结算系统 电商技术揭秘四&#xff1a;电商平台的物流管理系统 电商技术揭秘五&#xff1a;电商平台…

2024年MathorCup数学建模挑战赛A题B题C题D题思路模型代码

2024年MathorCup数学建模挑战赛 2024年MathorCup数学建模挑战赛A题B题C题D题思路模型代码开赛后第一时间更新&#xff1a;更新见文末 01 组织单位 主办单位&#xff1a;中国优选法统筹法与经济数学研究会 报名网址&#xff1a; https://www.saikr.com/vse/mathorcup/202…

如何使用Java和RabbitMQ实现延迟队列(方式二)?

前言 昨天写了一篇关于Java和RabbitMQ使用插件实现延迟队列功能的文章&#xff0c;今天来讲下另外一种方式&#xff0c;不需要RabbitMQ的插件。 前期准备&#xff0c;需要安装好docker、docker-compose的运行环境。 需要安装RabbitMQ的可以看下面这篇文章。 如何使用PHP和R…

AWS入门实践-在EC2上部署Wordpress网站

在AWS EC2上部署WordPress涉及到几个步骤&#xff0c;包括启动EC2实例、配置数据库、安装WordPress等。以下是详细的步骤和相应的命令脚本 第一步: 启动 EC2 实例 登录 AWS 控制台,进入 EC2 服务启动一个新的 EC2 实例,选择 Amazon Linux 2 AMI选择合适的实例类型(例如 t2.mi…

Java-接口-定义接口Filter及其实现类WordFilter

所谓&#xff1a;“纸上得来终觉浅&#xff0c;绝知此事要躬行。” 关于接口的知识&#xff0c;可以几分钟过一遍&#xff1a;Java-接口—知识&#xff08;基础&#xff09;-CSDN博客 现在就是练习time&#xff0c;先来看题&#xff1a; 定义一个接口 Filter&#xff0c;表示…

linux之shell命令

shell基础命令 浏览Linux 文件系统 Linux 系统目录结构 /bin&#xff1a; bin 是 Binaries (二进制文件) 的缩写, 这个目录存放着最经常使用的命令。 /boot&#xff1a; 这里存放的是启动 Linux 时使用的一些核心文件&#xff0c;包括一些连接文件以及镜像文件。 /dev &…