智能指针(1)
智能指针(1)
- 概念
- 内存泄漏
- 指针指针概念
- RAII
- 使用裸指针存在的问题
- 智能指针使用
- 分类
- unique(唯一性智能指针)
- 介绍
- 智能指针的仿写
- 代码理解
- 删除器
概念
内存泄漏
内存泄漏:程序中已动态分配的堆内存由于某些原因而未释放或无法释放,导致程序运行速度减慢甚至崩溃。
内存泄漏分为两类:
- 堆内存泄漏:在堆区申请了资源,结束时候没有将其堆区进行释放,导致该内存无法再次被使用。(或者说指向堆区内存的指针丢失)
- 资源泄漏:通常指系统资源,比如套接字,文件描述符等,因为这些在系统中都是有限制的,如果创建了而不归还,长时间就会耗尽资源,导致其他程序不可用。(例如:创建文件文件描述符(打开文件),但不归还(不关闭文件))。
指针指针概念
在java和C#语言中都有自动的垃圾回收机制,系统可以自动释放资源,为此在这些语言中,内存管理都不是问题。
C++中没有 垃圾回收机制,必须自动取释放资源,否则就会出现内存泄漏,因为在开发中内存泄漏很容易出现,但是又必须耗费大量精力去寻找解决内存泄漏,所以出现了智能指针。
int main() {int* ip=new int(10);if(ip!=nullptr) {//.....}//因为代码处理复杂,忘记释放return 0;
}
如上面就会出现内存泄漏,而解决内存泄漏最有效的方法就是指针指针。
智能指针:智能指针就是一个对象,智能指针对象中有一个指针,该指针存储的动态动态船舰对象的地址,用于生存期的控制,能够确保指针指针在对象离开作用域是自动调用析构函数来销毁对象(释放内存),防止内存泄漏。使用了智能指针就不会担心内存泄漏的问题了,也不需要手动释放内存了。
RAII
RAII是资源获取即初始化,使局部对象来管理资源的技术称为资源获取即初始化。
改方法就是充分利用了C++局部对象自动销毁的特性来控制资源的生命周期。
这些资源主要指操作系统中内存,套接字等,局部对象是指存储在栈中的对象,其生命周期靠操作系统来管理,无需人工介入。
RAII过程四个步骤:
- 设计一个类封装资源。
- 在构造函数中初始化。
- 在析构函数中执行销毁操作。
- 使用时定义一个类的局部对象。
class Object {int* ip;
public:Object(int val = 0) {ip = new int(val);cout << "create obj" << endl;}~Object() {delete ip;cout << "destory obj" << endl;}
};
void func() {Object obj(3);return;
}
int main() {func();return 0;
}
在func函数中创建了obj对象,obj也就是局部对象,在函数结束时,系统会自动释放销毁对象,也就自动调用了obj对象的析构函数。为此我们在使用资源的时候,在构造函数中进行初始化,在析构函数中进行销毁。
使用裸指针存在的问题
- 难以区分指针指向的是单一对象还是一组对象
- 使用完无法判断是否应该销毁对象,因为无法判断是否拥有指向的对象。(销毁之后仍然指向堆内存,但是堆内存已经释放)
- 在已经确定了销毁指针的情况下,也无法确定是用那个关键字来删除,例如delete,fopen等
- 即使确定了销毁指针的方法,也无法判断删除的对象是一组还是一个(delete,delete[])
- 上面问题就算都解决了,也难以保证在代码所有执行路径中有且只有一次销毁指针。
- 理论上没有办法来分辨一个指针是否处于悬挂状态。
智能指针使用
分类
C++11提供了4钟智能指针:auto_ptr,unique_ptr,shared_ptr和weak_ptr.
使用时需要引入头文件:#include < memory >
因为auto_ptr时C98标准中的,C98中没有右值引用,也没有move和forward,为此已经被C++11所弃用,所有此处不做过多介绍。
智能指针主要应用于多线程问题,因为在多线程中自主控制释放极为复杂,智能指针可以在线程结束时自动释放该对象的资源。
unique(唯一性智能指针)
介绍
我们以自定义的int类型指针为例:
int main() {unique_ptr<PtrInt> pa(new PtrInt(10));pa->Print();pa->SetValue(200);pa->Print();return 0;
}
我们创建了唯一性指针对象pa,指向船舰的PtrInt对象,可以通过指针来调用类的成员方法。并且会自动析构。
错误使用
my_unique_ptr<PtrInt> pa3(new PtrInt(3));//A
int main() {my_unique_ptr<PtrInt> pa(new PtrInt(10));PtrInt p(1);my_unique_ptr<PtrInt> pa1(&p);//BPtrInt* ip = new PtrInt(2);my_unique_ptr<PtrInt> pa2(ip);//C
}
A:使用智能指针管理全局变量是没有意义的,因为程序结束后,指针才销毁,都不如直接定义一个全局变量,其会在程序结束时自动销毁。(智能指针主要依赖局部对象来释放)
B:对象本身就是在栈中,而智能指针是处理堆区堆存,所以是错误的。
C:该方法本质上不是错误的,因为你用了裸指针,如果发现用了指针还没释放,就会释放两次,导致程序崩溃。
而这个唯一性指针是怎么实现的呢?
智能指针的仿写
template<class _Tp>
struct my_default_deleter
{void operator()(_Tp* ptr)const {delete ptr;}
};
template<class _Tp>
struct my_default_deleter<_Tp[]>
{void operator()(_Tp* ptr)const {delete []ptr;}
};
struct FileDeleter {void operator()(FILE* pf) const {fclose(pf);}};
template<class _Tp,class _Dp=my_default_deleter<_Tp>>
//template<class _Tp,class _Dp>
class my_unique_ptr//<_Tp[],_Dp>
{
public:using pointer = _Tp*;using elemtype_type = _Tp;using deleter_type = _Dp;
private:_Tp* ptr;deleter_type mDeleter;
public:/*deleter_type get_deleter()const {return mDeleter;}*/my_unique_ptr(_Tp* p = nullptr) :ptr(p) { cout << "create myuniqueptr" << endl; }//构造函数~my_unique_ptr() {//析构mDeleter(ptr);//mDeleter.operator()(ptr);//get_deleter()(ptr);ptr = nullptr;cout << "deatory myuniqueptr" << endl;}my_unique_ptr(const my_unique_ptr&) = delete;//删除拷贝构造my_unique_ptr& operator=(const my_unique_ptr&) = delete;//删除左值赋值重载my_unique_ptr(my_unique_ptr&& right) :ptr(right.ptr) {//移动构造right.ptr = nullptr;cout << "move create myuniqueptr" << endl;}my_unique_ptr& operator=(my_unique_ptr&& right) {//右值赋值重载if (this == &right) return *this;reset(right.release());//首先返回参数对象的资源指针,然后用该指针指向的资源代替现有指针的资源return *this;}pointer get() const { return ptr; }//返回指针_Tp& operator*()const { return *get(); }//指针解引用pointer operator->()const { return get(); }//指向符号重载pointer release() {//资源返回,将指向资源的指针返回pointer p = ptr;ptr = nullptr;return p;}void reset(pointer p = nullptr) {//资源移动,将形参指针指向的资源覆盖掉原本的资源,释放原本资源。mDeleter(ptr);ptr = p;}void swap(my_unique_ptr& u) {//交换指针指向的资源std::swap(this->ptr, u.ptr);}operator bool() const {//判断是否指向有效空间return get() != nullptr?true:false;}
};
上面就是指针指针的仿写,下面是使用
指向符重载,解引用:可以看出智能指针在这一块的使用和裸指针相同
int main() {my_unique_ptr<PtrInt> pa(new PtrInt(10));(*pa).SetValue(100);(*pa).Print();pa->SetValue(200);pa->Print();//pa.operator->()->Print();此处系统省去了一个指向符。return 0;
}
reset函数和release函数
release():返回指针
reset():资源覆盖,释放原本资源
int main() {my_unique_ptr<PtrInt> pa(new PtrInt(10));pa->Print();pa.reset(new PtrInt(100));//用新资源覆盖旧资源pa->Print();
}
int main() {my_unique_ptr<PtrInt> pa(new PtrInt(10));PtrInt* p = pa.get();//获取了指针,delete p;//errorPtrInt* ip = pa.release();//直接将指针指向nullptr,并且将指向资源的指针返回。
}
swap()函数:智能交换具名对象
int main() {my_unique_ptr<PtrInt> pa(new PtrInt(10));my_unique_ptr<PtrInt> pb(new PtrInt(20));pa->Print();pb->Print();pa.swap(pb);//只能和具名对象进行交换pa->Print();pb->Print();return 0;
}
判空:
判断指针是否为nullptr
int main() {unique_ptr<PtrInt> pa(new PtrInt(10));unique_ptr<PtrInt> pb(new PtrInt(20));my_unique_ptr<PtrInt> pc;if (pc) {//判断是否指向有效空间pc->Print();}
}
移动拷贝,移动赋值,拷贝构造,赋值重载
因为赋值重载和拷贝构造都是默认的浅拷贝,所以会出现两个指针指向同一资源,导致释放两次出现错误,所以呢删除了系统默认的拷贝构造函数和赋值重载。
而移动构造和移动赋值是可以实现的。这也就是唯一性智能指针的特点,有且只能管理一份资源。
int main() {my_unique_ptr<PtrInt> pa(new PtrInt(10));//my_unique_ptr<PtrInt> pb(pa);//浅拷贝 errormy_unique_ptr<PtrInt> pb(new PtrInt(20));//pa = pb;//浅拷贝 errmy_unique_ptr<PtrInt> pc(std::move(pa));pa = std::move(pb);return 0;
}
代码理解
my_unique_ptr<PtrInt> func(int x) {my_unique_ptr<PtrInt> pa(new PtrInt(x));return pa;
}
int main() {my_unique_ptr<PtrInt> pa(new PtrInt(10));pa = func(100);return 0;
}
首先在主函数中创建了只能指针对象,然后在func函数中船舰了智能指针的另一个对象,函数结束时使用移动构造来构建一个将亡值对象,然后移动赋值给pa对象。
void func(my_unique_ptr<PtrInt> px) {
}
int main() {my_unique_ptr<PtrInt> pa(new PtrInt(10));func(std::move(pa));pa->Print();return 0;
}
该程序会崩掉,因为把pa的资源移动到了px参数中,不存在拷贝构造,所以程序会因为pa指向为nullptr而崩掉。
void func(my_unique_ptr<PtrInt>& px) {px->Print();px->SetValue(200);px->Print();px.release();//my_unique_ptr<PtrInt> pb(std::move(px));
}
int main() {my_unique_ptr<PtrInt> pa(new PtrInt(10));func(pa);pa->Print();//errorreturn 0;
}
不能用移动语义接收智能指针,可以通过引用来接收智能指针,但不要在函数内部让让智能指针的资源移动走,否则智能指针指向nullptr。唯一性指针智能控制一个对象的资源。
删除器
在上面代码仿写中仿写了删除器,主要是为了使程序可用性更高,用到了仿函数,大家可以看一看以前的文章理解一下。
int main() {my_unique_ptr<FILE,FileDeleter> pfile(fopen("D:/tulun/ConsoleApplication6/ConsoleApplication6.cpp", "w"));//D:\tulun\ConsoleApplication6\ConsoleApplication6.cppreturn 0;
}
结果如下:
相关文章:
智能指针(1)
智能指针(1) 概念内存泄漏指针指针概念RAII使用裸指针存在的问题 智能指针使用分类unique(唯一性智能指针)介绍智能指针的仿写代码理解删除器 概念 内存泄漏 内存泄漏:程序中已动态分配的堆内存由于某些原因而未释放…...
Steemit 会颠覆 Quora/知乎 甚至 Facebook 吗?
Steemit是基于区块链技术的社交媒体平台,其独特的激励机制吸引了众多用户。然而,是否能够真正颠覆Quora、知乎甚至Facebook这些已经成为社交巨头的平台,仍然存在着许多未知因素。本文将探讨Steemit的优势和挑战,以及其在社交领域中…...
002Mybatis初始化引入
引入依赖 <dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId> </dependency> 自动检测工程中的DataSource创建并注册SqlSessionFactory实例创建并注册SqlSessionTemplate实例自…...
系统架构师之高内聚低耦合
一、概念: 标记耦合(Stamp Coupling)和数据耦合(Data Coupling)是软件设计中两种不同的耦合类型,它们之间的区别如下: 标记耦合:标记耦合是指模块之间通过参数传递标记或标识符来进…...
Netty核心源码剖析(二)
1.Netty接受请求过程源码剖析 1>.从之前的Netty启动过程源码剖析中,我们得知服务器最终注册了一个Accept事件等待客户端的连接.我们也知道,NioServerSocketChannel将自己注册到了bossGroup单例线程池(reactor线程)上,也就是EventLoop; 2>.先简单说下EventLoop的逻辑,Ev…...
「C/C++」C/C++ Lamada表达式
✨博客主页:何曾参静谧的博客 📌文章专栏:「C/C」C/C程序设计 相关术语 Lambda表达式:是C11引入的一种函数对象,可以方便地创建匿名函数。与传统的函数不同,Lambda表达式可以在定义时直接嵌入代码ÿ…...
bug(Tomcat):StandardContext.startInternal 由于之前的错误,Context[/day01]启动失败
引出 项目启动失败,一个困扰了一上午的bug 报错信息 org.apache.catalina.core.StandardContext.startInternal 一个或多个筛选器启动失败。完整的详细信息将在相应的容器日志文件中找到 org.apache.catalina.core.StandardContext.startInternal 由于之前的错误…...
Java性能权威指南-总结6
Java性能权威指南-总结6 垃圾收集入门垃圾收集概述GC算法选择GC算法 垃圾收集入门 垃圾收集概述 GC算法 JVM提供了以下四种不同的垃圾收集算法: Serial垃圾收集器 Serial垃圾收集器是四种垃圾收集器中最简单的一种。如果应用运行在Client型虚拟机(Windows平台上的32位JVM或…...
群的定义及性质
群的定义 设 < G , ⋅ > \left<G,\cdot\right> ⟨G,⋅⟩为独异点,若 G G G中每个元素关于 ⋅ \cdot ⋅都是可逆的,则称 < G , ⋅ > \left<G,\cdot\right> ⟨G,⋅⟩为群 由于群中结合律成立,每个元素的逆元是唯一的 …...
mac电脑git clone项目时报错证书过期和权限被拒绝
mac电脑使用git clone命令克隆项目时,一开始一直提示证书过期 SSL certificate problem: certificate has expired 执行以下代码关掉验证后,解决了这个问题 找到git目录 Git\git-cmd输入命令跳转到bin目录,cd bin输入命令运行git.exe执行关…...
【AIGC】Photoshop AI Beta版本安装使用(永久免费)
AIGC 大爆发 Adobe近日宣布,Photoshop(测试版)应用程序发布了生成式AI绘图,这是世界上第一个创意和设计工作流程的副驾驶,为用户提供了一种神奇的新工作方式。生成式AI绘图由Adobe Firefly提供支持,Adobe的…...
01 云原生生态系统解读
云计算的技术革命 互联网时代的历程 云计算到底是什么 云计算历程 云平台的优缺点 优势 稳定性:云平台大量资源,分布式集群部署,保障服务永不宕机,几个9弹性扩展:按需索取,一键秒级开通需要的资源安全性&…...
Java——Java易错选择题复习(2)(计算机网络)
1. 下面关于源端口地址和目标端口地址的描述中,正确的是( ) A. 在TCP/UDP传输段中,源端口地址和目的端口地址是不能相同的 B. 在TCP/UDP传输段中,源端口地址和目的端口地址必须是相同的 C. 在TCP/UDP传输段中ÿ…...
【HTML5系列教程】
《HTML5系列教程》目录大纲: 介绍 内容包括HTML简介、服务器的概念、B/S、C/S软件架构、前端与后端的开发内容、HTML发展历程、浏览器内核介绍、Web标准、WebStorm工具的使用、WebStorm常用快捷键、HTML常用标签 如:文本标签(span)、排版标签(div/p/h…...
二、电压源、电流源、受控源
点我回到目录 目录 理想电压源 理想电流源 受控源 电流源做功问题 电压源做功问题 理想电压源 •定义:两端电压保持定值或一定的时间函数,且电压值与流过它的电流i无关 •特点:理想电压源两端的电压由本身决定,与外电路无关…...
骨传导是哪个意思,推荐几款性能优的骨传导耳机
骨传导耳机是通过头部骨迷路传递声音,而不是直接通过耳膜的振动来传递声音。与传统的入耳式耳机相比,骨传导耳机不会堵耳朵,在跑步、骑车等运动时可以更好的接收外界环境音,保护听力,提升安全性。此外,骨…...
利用Taro打造灵活的移动App架构
最近公司的一些项目需要跨端框架,技术老大选了Taro,实践了一段时间下来,愈发觉得Taro是个好东西,所以在本篇文章中稍微介绍下。 什么是Taro? Taro(或称为Taro框架)是一种用于构建跨平台应用程…...
(转载)基于模拟退火算法的TSP问题求解(matlab实现)
1 理论基础 1.1 模拟退火算法基本原理 模拟退火(simulated annealing,SA)算法的思想最早是由Metropolis等提出的。其出发点是基于物理中固体物质的退火过程与一般的组合优化问题之间的相似性。模拟退火法是一种通用的优化算法,其物理退火过程由以下三部分组成&am…...
splitpcap 使用说明
背景 当PCAP原始文件特别巨大的时候,整个文件直接载入内存是相当耗时的,于是一个简单的想法是将大的PCAP切分成若干小PCAP。对于这个任务,现有工具splitcap是可以完成的。无论是按照主机对、还是按照五元组信息切分,splitcap都会…...
配置docker阿里云镜像加速
默认情况下docker安装镜像文件是从docker官方的镜像中心下载:https://hub.docker.com/ , 有时速度慢,可以通过配置docker阿里云镜像来加速,配置后,就从国内阿里云下载。 注册阿里云用户,登录->工作台-&g…...
《消息队列高手课》课程学习笔记(八)
如何实现高性能的异步网络传输? **异步与同步模型最大的区别是,同步模型会阻塞线程等待资源,而异步模型不会阻塞线程,它是等资源准备好后,再通知业务代码来完成后续的资源处理逻辑。**这种异步设计的方法,…...
DC电源模块在工业自动化的应用
BOSHIDA DC电源模块在工业自动化的应用 随着自动化技术的不断发展,DC电源模块已成为工业控制系统中不可或缺的一个组成部分。在许多自动化系统中,如机器人、控制器、PLC等,都需要使用到直流电源模块来提供稳定可靠的电源,以确保系…...
Java容器-集合
目录 1.Java容器概述 2.集合框架 3.Collection接口中的方法使用 4.iterator() 5.List接口 2.ArrayList、LinkedList、Vector相同点 3.不同点 1.ArrayList 2.LinkedList 3.Vector 4.Vector源码分析 5.ArrayList源码分析 6.LinkedList源码分析 6.List中的常用方法 …...
总结890
学习目标: 月目标:6月(线性代数强化9讲2遍,背诵15篇短文,考研核心词过三遍) 周目标:线性代数强化3讲,英语背3篇文章并回诵,检测 每日必复习(5分钟ÿ…...
2023年5月青少年机器人技术等级考试理论综合试卷(二级)
青少年机器人技术等级考试理论综合试卷(二级)2023.6 分数: 100 题数: 45 一、 单选题(共 30 题, 共 60 分) 1.下图中的凸轮机构使用了摆动型从动件的是? ( ) A.a B.b C.c D.d 试题类…...
2023CCPC河南省赛 VP记录
感觉现在的xcpc,风格越来越像CF,不是很喜欢,还是更喜欢多点算法题的比赛 VP银了,VP银也是银 感觉省赛都是思维题,几乎没有算法题,感觉像打了场大型的CF B题很简单没开出来,一直搞到最后&…...
【ECCV2022】DaViT: Dual Attention Vision Transformers
DaViT: Dual Attention Vision Transformers, ECCV2022 解读:【ECCV2022】DaViT: Dual Attention Vision Transformers - 高峰OUC - 博客园 (cnblogs.com) DaViT:双注意力Vision Transformer - 知乎 (zhihu.com) DaViT: Dual Attention Vision Trans…...
Apache 配置与应用
Apache 配置与应用 一、构建虚拟 Web 主机httpd服务支持的虚拟主机类型包括以下三种: 二、基于域名的虚拟主机1.为虚拟主机提供域名解析方法一:部署DNS域名解析服务器 来提供域名解析方法二:在/etc/hosts 文件中临时配置域名与IP地址的映射关…...
OpenGL 纹理
1.简介 纹理是一个2D图片(甚至也有1D和3D的纹理),它可以用来添加物体的细节;你可以想象纹理是一张绘有砖块的纸,无缝折叠贴合到你的3D的房子上,这样你的房子看起来就像有砖墙外表了。 为了能够把纹理映射(M…...
Jeston Orin Nnao 安装pytorch与torchvision环境
大家好,我是虎哥,Jeston Orin nano 8G模块,提供高达 40 TOPS 的 AI 算力,安装好了Jetpack5.1之后,我们需要配置一些支持环境,来为我们后续的深度学习开发提供支持。本章内容,我将主要围绕安装对…...
昭通建设局网站/网站一键生成
strip_whitespace() php读取txt文件并分割行替换空字符串 $handler opendir(zhuzhuoquan);//文件夹名 $ii0; $str ; while( ($filename readdir($handler)) ! false ) { if($filename . || $filename.. || $filenameviews) continue;$ii;//echo $ii.. .$filename.<br…...
老司机做爰网站老师影音/公司网站怎么申请怎么注册
[转] 字符编码笔记:ASCII,Unicode和UTF-8这是一篇关于字符集的很详细的文章,连我都能看明白,所以转来。文章来源: http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html字符编码笔记:ASCII࿰…...
做前端项目怎么进行网站切图/营销心得体会感悟300字
ListView使用多选模式好处 交互与数据分离,在多选状态下不需要修改数据源,在最后确定的时候获取选择索引来确定选择的数据。 ListView模式 CHOICE_MODE_NONE:普通模式;CHOICE_MODE_SINGLE:单选模式;CHOICE_…...
织梦做网站视频教程/营销推广方案设计
方一 Integer[] xnew Integer[]{4,6,9,10}; Set<Integer> set new HashSet<>() ; Collections.addAll(set,x);for(Integer ele:set){System.out.println(ele); }方二 Set<Integer> set new HashSet<>(Arrays.asList(4,6,9,10)) ;...
网站开发公司怎么查询/新闻摘抄2022最新5篇
目录 1、数据报方式 1.1、数据报方式的原理 1.2、数据报方式的特点 2、虚电路方式 2.1、虚电路方式简介 2.2、虚电路方式的工作原理(流程) 2.3、虚电路方式的特点 3、数据报服务和虚电路服务的对比 分组交换根据其通信子网向端点系统提供的服务&…...
商机互联做的网站和推广怎么样/seo网站优化系统
| | | | HEADING | | ---------------- | | | | | | ---------------- | | | | REPORT | | ---------------- | | | | | | ---------------- | | | | ENDING | | ---------------- | | | | | | ---------------- | | | |...