当前位置: 首页 > news >正文

【C++】C++11——智能指针、内存泄漏、智能指针的使用和原理、RAII、auto_ptr、unique_ptr、shared_ptr、weak_ptr

文章目录

  • C++11
    • 7.智能指针
      • 7.1内存泄漏
      • 7.2智能指针的概念
      • 7.3智能指针的使用
        • 7.3.1 auto_ptr
        • 7.3.2 unique_ptr
        • 7.3.3 shared_ptr
        • 7.3.4 weak_ptr

C++11

在这里插入图片描述

7.智能指针

7.1内存泄漏

  什么是内存泄漏:

  内存泄漏指因为疏忽或错误造成程序未能释放已经不再使用的内存的情况。内存泄漏并不是指内存在物理上的消失,而是应用程序分配某段内存后,因为设计错误,失去了对该段内存的控制,因而造成了内存的浪费。

  内存泄漏通常由于程序在设计上的缺陷或错误,例如动态分配内存后,未在合适的时间或无法正确释放该段内存,而导致的。内存泄漏通常需要程序员通过分析程序源代码来识别和修复。

  内存泄漏的危害:

  在某些情况下,内存泄漏可能并不严重,或者能够被常规手段检测出来。然而,如果内存泄漏持续存在并导致大量可用内存被分配掉,可能会导致计算机性能显著下降,甚至导致全部或部分设备停止正常工作,或者应用程序崩溃。如果长期运行的程序出现内存泄漏,影响很大,如操作系统、后台服务等等,出现内存泄漏会导致响应越来越慢,最终卡死。

  
  内存泄漏的示例:

void MemoryLeaks()
{// 1.内存申请了忘记释放int* p1 = (int*)malloc(sizeof(int));int* p2 = new int;// 2.异常安全问题int* p3 = new int[10];Func(); // 这里Func函数抛异常导致 delete[] p3未执行,p3没被释放.delete[] p3;
}

  
  如何避免内存泄漏:

  (1)合理使用动态内存:尽量避免使用动态内存分配,因为使用动态内存分配后需要手动释放内存,否则会造成内存泄漏。如果必须使用动态内存分配,应该确保在使用完毕后及时释放内存。

  (2)及时释放内存:在使用完动态分配的内存后,必须及时释放它们,以避免内存泄漏。在C++中,可以在析构函数中释放内存;在C中,可以使用free()函数来释放内存。

  (3)使用智能指针:智能指针是一种能够自动管理内存的机制,可以避免由于忘记释放内存而导致的内存泄漏。 C++11标准库提供了多种类型的智能指针,如unique_ptr、shared_ptr和weak_ptr,可以根据具体情况选择合适的智能指针类型来管理内存。

  (4)尽量避免循环引用:如果两个对象之间存在相互引用关系,并且没有任何其他对象或机制来打破循环引用,那么就会导致内存泄漏。因此,在设计程序时应该尽可能避免循环引用,或者使用其他机制来打破循环引用。

  (5)使用垃圾回收机制:一些编程语言提供了垃圾回收机制,可以自动检测并回收不再使用的内存。这些语言包括Java、Python和JavaScript等。如果使用这些语言,可以充分利用它们的垃圾回收机制来避免内存泄漏。

  (6)定期检查程序:定期检查程序是否存在内存泄漏是一种有效的手段。可以使用一些工具来检测程序中的内存泄漏, 例如Valgrind和AddressSanitizer等。这些工具可以帮助发现程序中的内存泄漏问题,并提供修复建议。

            

7.2智能指针的概念

  智能指针是一种C++中的对象,它用于管理动态分配的内存,并自动释放内存以避免内存泄漏。智能指针的工作原理是,当智能指针超出其作用域或被销毁时,它会自动释放它所管理的内存。

  智能指针的常见类型包括unique_ptr、shared_ptr和weak_ptr。 unique_ptr表示只有一个指针指向动态分配的内存,当unique_ptr被销毁时,它所管理的内存会被自动释放。shared_ptr表示多个指针可以指向同一块动态分配的内存,当最后一个指向该内存的shared_ptr被销毁时,它所管理的内存会被自动释放。weak_ptr是shared_ptr的一个别名,它不持有动态分配的内存的任何所有权,而是用于与其他智能指针一起使用,以避免循环引用。

  下面是一个简单的unique_ptr使用的例子:

  在这个例子中,我们首先定义了一个名为MyStruct的结构体,它有一个整数值。接下来,在main函数中,我们使用std::unique_ptr< MyStruct >类型定义了一个智能指针对象ptr,并使用new操作符分配了一个新的MyStruct对象,将它的指针赋给了ptr。我们可以通过ptr->value来访问MyStruct对象的值。最后,当main函数返回时,ptr将自动释放它所管理的内存,避免了内存泄漏。

#include <iostream>  
#include <memory>  struct MyStruct {  int value;  MyStruct(int v) : value(v) {}  
};  int main() {  std::unique_ptr<MyStruct> ptr(new MyStruct(10));  std::cout << "Value: " << ptr->value << std::endl;  return 0;  
}

            

7.3智能指针的使用

   RAII:

  RAII是资源获取就是初始化的简称,是C++语言的一种管理资源、避免泄漏的惯用法。

  RAII的核心思想是,定义一个类来封装资源的分配和释放,在构造函数完成资源的分配和初始化,在析构函数完成资源的清理。这样可以保证资源的正确初始化和释放,防止内存泄漏。

  利用C++构造的对象最终会被销毁的原则,当对象被销毁时,会自动调用其析构函数,释放对象生命期内控制的资源。

  RAII有两个好处:

  (1)不需要显式地释放资源;

  (2)采用这种方式,对象所需的资源在其生命期内始终保持有效。

// 使用RAII思想设计的SmartPtr类
template<class T>
class SmartPtr 
{
public:SmartPtr(T* ptr = nullptr): _ptr(ptr){}~SmartPtr(){if(_ptr)delete _ptr;}private:T* _ptr;
};int div()
{int a, b;cin >> a >> b;if (b == 0)throw invalid_argument("除0错误");return a / b;
}void Func()
{ShardPtr<int> sp1(new int);ShardPtr<int> sp2(new int);cout << div() << endl;
}int main()
{try {Func();}catch(const exception& e){cout<<e.what()<<endl;}return 0;
}

  

  上述的SmartPtr还不能将其称为智能指针,因为它还不具有指针的行为。指针可以解引用,也可以通过->去访问所指空间中的内容,因此:AutoPtr模板类中还得需要将* 、->重载下,才可让其像指针一样去使用。

  
  总结一下智能指针的原理:

  (1)RAII特性

  (2)重载operator*和opertaor->,具有像指针一样的行为

template<class T>
class SmartPtr 
{
public:SmartPtr(T* ptr = nullptr): _ptr(ptr){}~SmartPtr(){if(_ptr)delete _ptr;}T& operator*() {return *_ptr;}T* operator->() {return _ptr;}private:T* _ptr;
};struct Date
{int _year;int _month;int _day;
};int main()
{SmartPtr<int> sp1(new int);*sp1 = 10cout<<*sp1<<endl;SmartPtr<int> sparray(new Date);// 需要注意的是这里应该是sparray.operator->()->_year = 2018;// 本来应该是sparray->->_year这里语法上为了可读性,省略了一个->sparray->_year = 2018;sparray->_month = 1;sparray->_day = 1;
}

  

7.3.1 auto_ptr

std::auto_ptr

  C++98版本的库中就提供了auto_ptr的智能指针。

  注意:auto_ptr被认为是一个失败的设计:

  (1)所有权的转移不清晰:auto_ptr在构造时获取对象的所有权,但可以通过赋值操作将所有权转移给另一个auto_ptr。这样会造成原来的auto_ptr指针悬空,程序直接崩溃。

  (2)无法在STL容器中使用:auto_ptr的拷贝构造函数会进行所有权的转移,这使得它难以被用在STL容器中。因为在容器中添加元素时,会涉及到拷贝操作,这可能会导致所有权的转移,从而使得容器中的元素所指向的对象被释放,引起程序错误。

  (3)nullptr的问题:auto_ptr无法安全地处理nullptr。如果你试图让一个auto_ptr指向一个nullptr,它会在析构时释放该指针,即使该指针从未被分配过内存。

  (4)不支持自定义删除器:auto_ptr只能使用默认的delete操作符来释放内存,无法使用自定义的删除器。这限制了auto_ptr的灵活性。基于以上原因,现代C++编程中更推荐使用unique_ptr、shared_ptr和weak_ptr来替代auto_ptr。

  auto_ptr的实现原理:管理权转移的思想,下面简化模拟实现了一份bit::auto_ptr来了解它的原理:

template<class T>
class auto_ptr
{
public:auto_ptr(T* ptr):_ptr(ptr){}~auto_ptr(){cout << "delete:" << _ptr << endl;delete _ptr;}T& operator*(){return *_ptr;}T* operator->(){return _ptr;}//管理权转移auto_ptr(auto_ptr<T>& ap):_ptr(ap._ptr){ap._ptr = nullptr;}private:T* _ptr;
};

  

7.3.2 unique_ptr

std::unique_ptr

  unique_ptr是C++11标准库中的一种智能指针,它持有对对象的独有权,即两个unique_ptr不能指向同一个对象,不能进行复制操作,只能进行移动操作。 当unique_ptr超出其作用域或被销毁时,它所管理的内存会被自动释放,有效避免了内存泄漏问题。unique_ptr是一种方便、安全、自动管理内存的机制,可以有效避免内存泄漏问题。

  unique_ptr的实现原理:简单粗暴的防拷贝,下面简化模拟实现了一份unique_ptr来了解它的原理:

template<class T>
class unique_ptr
{
public:unique_ptr(T* ptr):_ptr(ptr){}~unique_ptr(){cout << "delete:" << _ptr << endl;delete _ptr;}T& operator*(){return *_ptr;}T* operator->(){return _ptr;}//禁止拷贝unique_ptr(unique_ptr<T>& ap) = delete;unique_ptr<T>& operator=(unique_ptr<T>& ap) = delete;private:T* _ptr;
};

  

7.3.3 shared_ptr

std::shared_ptr

  shared_ptr是一种C++中的智能指针,它可以记录有多少个shared_ptrs指向一个对象。当最后一个这样的指针被销毁时,也就是最后一个指向对象的shared_ptr被销毁时,该对象会被自动删除,这在非环形数据结构中防止资源泄露很有帮助。

  它与unique_ptr不同,shared_ptr允许多个指针指向同一个对象,并共同拥有该对象的所有权。当最后一个shared_ptr被销毁时,它所指向的对象也会被自动删除。

  
  shared_ptr的实现原理:

  shared_ptr在其内部,给每个资源都维护了着一份计数,用来记录该份资源被几个对象共享。 在对象被销毁时(也就是析构函数调用),就说明自己不使用该资源了,对象的引用计数减一。

  如果引用计数是0,就说明自己是最后一个使用该资源的对象,必须释放该资源; 如果不是0,就说明除了自己还有其他对象在使用该份资源,不能释放该资源,否则其他对象就成野指针了。

  shared_ptr的实现原理:使用了引用计数,下面简化模拟实现了一份shared_ptr来了解它的原理:

template<class T>
class shared_ptr
{
public:// RAIIshared_ptr(T* ptr = nullptr):_ptr(ptr), _pcount(new int(1)){}~shared_ptr(){if (--(*_pcount) == 0){cout << "delete:" << _ptr << endl;delete _ptr;delete _pcount;}}T& operator*(){return *_ptr;}T* operator->(){return _ptr;}shared_ptr(const shared_ptr<T>& sp):_ptr(sp._ptr), _pcount(sp._pcount){++(*_pcount);}shared_ptr<T>& operator=(const shared_ptr<T>& sp){if (_ptr == sp._ptr)return *this;if (--(*_pcount) == 0){delete _ptr;delete _pcount;}_ptr = sp._ptr;_pcount = sp._pcount;++(*_pcount);return *this;}int use_count() const{return *_pcount;}T* get() const{return _ptr;}private:T* _ptr;int* _pcount;
};

  

7.3.4 weak_ptr

std::weak_ptr

  weak_ptr是C++中为了配合shared_ptr解决循环引用问题而引入的一种智能指针。

  weak_ptr可以从一个shared_ptr或另一个weak_ptr对象构造,它的构造和析构不会引起shared_ptr引用记数的增加或减少。 weak_ptr的一个重要用途是通过lock获得this指针的shared_ptr,使对象自己能够生产shared_ptr来管理自己。总的来说,weak_ptr主要用于配合shared_ptr,以避免内存泄漏。

  下面简化模拟实现了一份weak_ptr来了解它的原理:

template<class T>
class weak_ptr
{
public:weak_ptr():_ptr(nullptr){}weak_ptr(const shared_ptr<T>& sp):_ptr(sp.get()){}weak_ptr<T>& operator=(const shared_ptr<T>& sp){_ptr = sp.get();return *this;}T& operator*(){return *_ptr;}T* operator->(){return _ptr;}
private:T* _ptr;
};

  

相关文章:

【C++】C++11——智能指针、内存泄漏、智能指针的使用和原理、RAII、auto_ptr、unique_ptr、shared_ptr、weak_ptr

文章目录 C117.智能指针7.1内存泄漏7.2智能指针的概念7.3智能指针的使用7.3.1 auto_ptr7.3.2 unique_ptr7.3.3 shared_ptr7.3.4 weak_ptr C11 7.智能指针 7.1内存泄漏 什么是内存泄漏&#xff1a; 内存泄漏指因为疏忽或错误造成程序未能释放已经不再使用的内存的情况。内存泄漏…...

EDUSRC-记某擎未授权与sql注入

目录 360天擎 - 未授权与sql注入 信息收集 FOFA语法 鹰图搜索 360天擎未授权访问 - 数据库信息泄露 漏洞复现 修复方案 360天擎终端安全管理系统ccid处SQL注入 漏洞复现 手动测试方法 修复方案 360天擎 - 未授权与sql注入 通常访问的页面如下&#xff0c;存在登录框…...

1688拍立淘API接口分享

拍立淘接口&#xff0c;顾名思义&#xff0c;就是通过图片搜索到相关商品列表。通过此接口&#xff0c;可以实现图片搜索爆款商品等功能。 接口地址&#xff1a;1688.item_search_img 公共参数 名称类型必须描述keyString是调用key&#xff08;必须以GET方式拼接在URL中&…...

昇腾910使用记录

一. 压缩文件和解压文件 1. 压缩文件 tar -czvf UNITE-main.tar.gz ./UNITE-main/2. 解压文件 tar -xvf ./UNITE-main/二. CUDA更改为NPU data[label] data[label].cuda() data[instance] data[instance].cuda() data[image] data[image].cuda()更改为 data[label] da…...

从一部iPhone手机看芯片的分类

目录 问题 iPhone X 手机处理器&#xff1a;A11 iPhone X 的两大存储芯片 数字 IC CPU&#xff1a;计算设备的运算核心和控制核心 GPU&#xff1a;图形处理器 ASIC&#xff1a;为解决特定应用问题而定制设计的集成电路 存储芯片&#xff1a;DRAM 和 NAND Flash iPhone…...

arm day 7

完成字符串收发函数的封装并且验证现象&#xff0c;一个字符串发送接受后会有‘\n’ \r src/uart.c #include"uart.h"void uart4_init() {//设置UART4的RCc时钟使能//RCC_MP_APB1ENSETR[16]->1RCC->MP_APB1ENSETR | (0x1<<16);//设置GPIOB和GPIOG的时钟…...

Java基础面试-面向对象

什么是面向对象&#xff1f; 对比面向过程&#xff0c;是两种不同的处理问题角度 面向过程更注重事情的每一个步骤及顺序&#xff0c;面向对象更注重事情有哪些参与者&#xff08;对象&#xff09;&#xff0c;及各自需要做什么 比如洗衣机洗衣服 面向过程会将任务拆解成一系…...

GCC vs. G++:C 与 C++ 编译器的差异和比较

本文将介绍 GCC&#xff08;GNU Compiler Collection&#xff09;和 G 编译器的区别&#xff0c;并对它们在 C 和 C 程序开发中的特性和用法进行比较和总结。 引言 在 C 和 C 程序开发中&#xff0c;选择合适的编译器是至关重要的。GCC&#xff08;GNU Compiler Collection&a…...

MAC m系列docker login报错

错误&#xff1a;ERROR: failed to solve: XXX error getting credentials - err: exit status 1, out: 解决&#xff1a; vi ~/.docker/config.jsonzsxzsx [15时55分55秒] [~] { {"auths": {"harbor-g42c.corp.matrx.team": {"auth": "…...

Redis通用指令和五大基本数据类型常用指令总结

通用指令 keys parttern 查询key (parttern即通配符&#xff0c;不是正则表达式&#xff0c;例如 keys a? 匹配以a开头的长度为2的key) del key 删除key exists key 获取key是否存在 type key 获取key的类型 expire key seconds 为指定key设置有效期&#xff0c;单位秒 …...

uCharts常用图表组件demo

带渐变阴影的曲线图 <view class"charts-box"><qiun-data-charts type"area" :opts"opts" :chartData"chartData" :ontouch"true":background"rgba(256,256,256,0)" /> </view>data(){return{…...

VNC:Timed out waiting for a response from the computer

VNC的服务端使用的是TigerVNC&#xff0c;客户端使用的是RealVNC TigerVNC按其他博客配好后&#xff0c;防火墙ip什么的都配了&#xff0c;vnc客户端怎么连都是超时。 这里建议大家可以尝试一下重启服务器。我的是CentOS的 shutdown -r now 配了2天&#xff0c;最后服务器重启…...

Kotlin 协程 知识点

Android 上的 Kotlin 协程 | Android Developers (google.cn) 官方网址 1.什么是协程&#xff1f; 我觉得协程就是kotlin中一种优雅的实现异步请求 协程&#xff08;Coroutines&#xff09;是一种轻量级的并发编程概念&#xff0c;旨在简化异步编程和并发任务的处理。它是…...

简单大方的自我介绍 PPT 格式

自我介绍是展示自己的机会&#xff0c;同时也是展现自信和魅力的重要时刻。通过简单大方的PPT格式&#xff0c;可以更好地展示自己的个性和才华。下面是一些建议&#xff0c;帮助你在自我介绍中展现自信和魅力。 1. 打造简洁而有吸引力的PPT布局&#xff1a; - 选择简洁大方的背…...

panads操作excel

panads简介 pandas是基于Numpy创建的Python包&#xff0c;内置了大量标准函数&#xff0c;能够高效地解决数据分析数据处理和分析任务&#xff0c;pandas支持多种文件的操作&#xff0c;比如Excel&#xff0c;csv&#xff0c;json&#xff0c;txt 文件等&#xff0c;读取文件之…...

【MySQL】联合查询、子查询、合并查询

这里提供了三个表&#xff1a; 表1&#xff1a; mysql> select * from class; -------------- | id | name | -------------- | 1 | 一班 | | 2 | 二班 | | 3 | 三班 | -------------- 3 rows in set (0.01 sec) 表2&#xff1a; mysql> select * fro…...

小程序中如何设置所服务地区的时区

在全球化的背景下&#xff0c;小程序除了在中国使用外&#xff0c;还为海外的华人地区提供服务。例如我们采云小程序为泰国、阿根廷、缅甸等国家的商家就提供过微信小程序。这些商家开通小程序&#xff0c;为本地的华人提供服务。但通常小程序的开发者/服务商位于中国&#xff…...

Linux环境安装mysql8.0

1个人习惯我喜欢给软件安装在/use/local下&#xff0c;我使用的finalshell软件&#xff0c;直接手动新建一个文件夹名字为mysql 2下载mysql wget https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-8.0.20-linux-glibc2.12-x86_64.tar.xz 3解压文件 tar -xvf mysql-8.0.2…...

STM32_DMA_多通道采集ADC出现错位现象

STM32_DMA_多通道采集ADC出现错位现象 问题描述&#xff1a; adcSensorValue[0],adcSensorValue[3],adcSensorValue[6]… //存储通道1数据 adcSensorValue[1],adcSensorValue[4],adcSensorValue[7]… //存储通道2数据 adcSensorValue[2],adcSensorValue[5],adcSensorValue[8]……...

Linux内存管理 (2):memblock 子系统的建立

前一篇&#xff1a;Linux内存管理 (1)&#xff1a;内核镜像映射临时页表的建立 文章目录 1. 前言2. 分析背景3. memblock 简介3.1 memblock 数据结构3.2 memblock 接口 4. memblock 的构建过程 1. 前言 限于作者能力水平&#xff0c;本文可能存在谬误&#xff0c;因此而给读者…...

Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例

使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件&#xff0c;常用于在两个集合之间进行数据转移&#xff0c;如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model&#xff1a;绑定右侧列表的值&…...

centos 7 部署awstats 网站访问检测

一、基础环境准备&#xff08;两种安装方式都要做&#xff09; bash # 安装必要依赖 yum install -y httpd perl mod_perl perl-Time-HiRes perl-DateTime systemctl enable httpd # 设置 Apache 开机自启 systemctl start httpd # 启动 Apache二、安装 AWStats&#xff0…...

高频面试之3Zookeeper

高频面试之3Zookeeper 文章目录 高频面试之3Zookeeper3.1 常用命令3.2 选举机制3.3 Zookeeper符合法则中哪两个&#xff1f;3.4 Zookeeper脑裂3.5 Zookeeper用来干嘛了 3.1 常用命令 ls、get、create、delete、deleteall3.2 选举机制 半数机制&#xff08;过半机制&#xff0…...

spring:实例工厂方法获取bean

spring处理使用静态工厂方法获取bean实例&#xff0c;也可以通过实例工厂方法获取bean实例。 实例工厂方法步骤如下&#xff1a; 定义实例工厂类&#xff08;Java代码&#xff09;&#xff0c;定义实例工厂&#xff08;xml&#xff09;&#xff0c;定义调用实例工厂&#xff…...

Web 架构之 CDN 加速原理与落地实践

文章目录 一、思维导图二、正文内容&#xff08;一&#xff09;CDN 基础概念1. 定义2. 组成部分 &#xff08;二&#xff09;CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 &#xff08;三&#xff09;CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 &#xf…...

OPENCV形态学基础之二腐蚀

一.腐蚀的原理 (图1) 数学表达式&#xff1a;dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一&#xff0c;腐蚀跟膨胀属于反向操作&#xff0c;膨胀是把图像图像变大&#xff0c;而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...

基于IDIG-GAN的小样本电机轴承故障诊断

目录 🔍 核心问题 一、IDIG-GAN模型原理 1. 整体架构 2. 核心创新点 (1) ​梯度归一化(Gradient Normalization)​​ (2) ​判别器梯度间隙正则化(Discriminator Gradient Gap Regularization)​​ (3) ​自注意力机制(Self-Attention)​​ 3. 完整损失函数 二…...

从“安全密码”到测试体系:Gitee Test 赋能关键领域软件质量保障

关键领域软件测试的"安全密码"&#xff1a;Gitee Test如何破解行业痛点 在数字化浪潮席卷全球的今天&#xff0c;软件系统已成为国家关键领域的"神经中枢"。从国防军工到能源电力&#xff0c;从金融交易到交通管控&#xff0c;这些关乎国计民生的关键领域…...

聚六亚甲基单胍盐酸盐市场深度解析:现状、挑战与机遇

根据 QYResearch 发布的市场报告显示&#xff0c;全球市场规模预计在 2031 年达到 9848 万美元&#xff0c;2025 - 2031 年期间年复合增长率&#xff08;CAGR&#xff09;为 3.7%。在竞争格局上&#xff0c;市场集中度较高&#xff0c;2024 年全球前十强厂商占据约 74.0% 的市场…...

大数据驱动企业决策智能化的路径与实践

&#x1f4dd;个人主页&#x1f339;&#xff1a;慌ZHANG-CSDN博客 &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; 一、引言&#xff1a;数据驱动的企业竞争力重构 在这个瞬息万变的商业时代&#xff0c;“快者胜”的竞争逻辑愈发明显。企业如何在复杂环…...