news 2026/8/29 6:59:17

内存管理 + 模版初阶

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
内存管理 + 模版初阶

内存管理 + 模版初阶

  • 一、内存分布
  • 二、new 和 delete
  • 二、new 和 delete的实现原理
  • 四、定位 new
  • 五、模板
    • 5.1 函数模板
      • 5.1.1函数模板的格式
      • 5.1.2函数模板实例化
      • 5.1.3函数模板匹配规则
    • 5.2 类模板

一、内存分布

  • 栈区:用来存储局部数据。栈区是向下生长的。
  • 内存映射段:是高效的I/O映射方式,用于装载一个共享的动态内存库。用户可使用系统接口
    创建共享内存,做进程间通信。
  • 堆区:用于动态内存分配。堆区是向上生长的。
  • 代码段:存储可执行的代码和只读常量。
  • 数据段:存储全局数据和静态数据。

二、new 和 delete

  • newdelete都是关键字,并不是函数。它们的作用是向堆区申请和释放资源。
  • new 和 delete 对于内置类型:与malloc / calloc 、free类似,但是new 和 delete更加简洁,同时能够初始化。(malloc/calloc申请空间失败会返回空指针,而new申请空间失败会抛异常)。
#include<iostream>usingnamespacestd;voidtest1(){//场景1://申请一个整型类型的空间//以前的写法int*ptr1=(int*)malloc(sizeof(int));if(ptr1==nullptr){perror("malloc fail");exit(1);}//如果要求同时初始化,就应该使用calloc函数,但是只能全部初始化为0//释放空间free(ptr1);ptr1=nullptr;//新的写法// new 数据类型int*ptr2=newint;//如果要求同时初始化// new 数据类型(初始化值)int*ptr3=newint(1);//释放空间deleteptr2;deleteptr3;//////////////////////////////////////////////////////////////////////////////////////////////场景2://申请一个连续空间的整型数组//以前写法int*p1=(int*)malloc(sizeof(int)*4);if(p1==nullptr){perror("malloc fail");exit(1);}//释放空间free(p1);p1=nullptr;//新的写法// new 数据类型[数据个数]int*p2=newint[4];//如果要求同时初始化// new 数据类型[数据个数] {初始化值}int*p3=newint[4]{1,2,3,4};for(inti=0;i<4;i++){cout<<*(p3+i);}cout<<endl;//释放空间delete[]p2;delete[]p3;}intmain(){test1();return0;}
  • 这里要明白new 和 delete的使用方法。同时申请的是连续空间,应该使用delete[ ] 进行释放空间,保证配套使用。
  • C++之所以创建new和delete,是为了解决自定义类型。
#include<iostream>usingnamespacestd;classA{public:A(int_a=0){cout<<"A()"<<endl;}~A(){cout<<"~A()"<<endl;}private:int_a;};voidtest2(){//malloc实现A*ptr1=(A*)malloc(sizeof(A));if(ptr1==nullptr){perror("malloc fail");exit(1);}//new实现A*ptr2=newA;//释放空间free(ptr1);ptr1=nullptr;deleteptr2;}

可以发现new和delete会自动调用构造函数和析构函数,而malloc不会。

voidtest(){//支持初始化A*ptr3=newA(1);A*ptr6=newA(2);//自定义类型的数组A*ptr4=newA[2];//自定义类型数组的初始化A*ptr5=newA[2]{1,2};delete[]ptr5;//拷贝构造来初始化A*ptr7=newA[2]{*ptr3,*ptr6};//匿名对象初始化A*ptr8=newA[2]{A(1),A(2)};delete[]ptr8;delete[]ptr7;delete[]ptr4;deleteptr3;deleteptr6;}

二、new 和 delete的实现原理

  • new 的实现原理

1.调用operator new()函数来实现申请空间资源。

operator new()也是通过malloc来实现的,但是检查申请空间是否成功,并不是看返回的指针是否为nullptr,而是通过抛异常来实现的。

2.调用析构函数来进行初始化。

  • new[T] 的实现原理

1.调用operator new[ ],operator new[ ] 中调用operator new()完成对T个对象空间的申请,同时还会在申请空间的初始位置额外开一块空间(用来存放T,以便析构时知道析构多少空间),返回偏移后的指针。
2.调用T次构造函数,完成对对象空间的初始化。

  • delete的实现原理

1.调用析构函数,对自定义类型中的类成员进行空间释放。
2.调用operator delete()函数 ,实现对自定义类型的空间释放。

operator delete()也是通过free来释放内存空间的。

  • delete[ ]实现原理

1.指针偏移读取到要析构T次,然后调用T次析构函数,完成对对象空间内申请资源的成员的空间的释放。
2.调用operator delete[ ] ,operator delete[ ] 调用operator delete()完成对T个对象空间的释放。

四、定位 new

定位new是对已经分配好空间的内存调用析构函数进行初始化。

格式: new(place_adress)type 或者是 new(place_adress)type(initializer-list)
  • place_adress -> 分配空间的地址
  • type -> 数据类型
  • initialzer-list 初始化列表

常应用于内存池方面。

voidtest3(){A*ptr1=(A*)malloc(sizeof(A));new(ptr1)A(1);ptr1->~A();free(ptr1);A*ptr2=(A*)operatornew(sizeof(A));new(ptr2)A(3);ptr2->~A();operatordelete(ptr2);}

重点:malloc / free 和 new / delete 的区别

  • malloc申请空间失败,返回NULL;new不需要,new需要捕获异常。
  • 申请自定义类型空间时,malloc/free只会开辟和释放空间,不会调用构造函数和析构函数。new会在开辟好空间后,调用构造函数进行初始化,delete会在释放空间之前会调用析构函数,对对象内申请资源进行释放。
  • malloc/free 是函数,而new / delete是操作符。
  • malloc对申请的空间不会初始化,new会对申请的空间进行初始化。
    malloc返回void类型,new后面跟着数据类型,会返回该类型的指针。
  • malloc需要手动计算申请空间大小,new不需要,new后面有数据类型,多个对象,只需在[ ]内明确对象个数。

五、模板

模板分为函数模板类模板
模板不建议声明和定义分离,会出现链接错误。

5.1 函数模板

5.1.1函数模板的格式

template<typename T1,typename T2,……,typename Tn> 返回类型 函数名(参数列表) {}
template<classT>voidswap(constT&x,constT&y){T tmp=x;x=y;y=tmp;}
  • typename 是关键字,意思是类型名,也可以用class来代替。
  • T是指数据类型

5.1.2函数模板实例化

函数模板示例化分为隐式实例化显式实例化
隐式实例化:通过实参,编译器来推断数据类型。

template<classT>TAdd(constT&x,constT&y){return(x+y);}intmain(){cout<<Add(2,3)<<endl;;//自动推导T类型为intcout<<Add(1.2,3.4)<<endl;//自动推导T类型为double/* Add(1.2,3); 这样的语句会报错,编译器推导不出T的类型到底是int还是double */return0;}

显式实例化:手动来确定类型。

template<classT1,classT2>T2Add(constT1&x,constT2&y){return(x+y);}intmain(){cout<<Add<int,double>(1,2.2)<<endl;return0;}

如果实参类型与手动设置类型不一致,会进行类型转化,如果不能类型转换,就会报错。

5.1.3函数模板匹配规则

1. 非模板函数与函数函数可以以相同名字存在,同时也允许模板函数的实例化与非模板函数一致。
2. 非模板函数与函数模板实例化后一致,那么在调用函数时,优先使用非模板函数。如果函数模板能够产生更加匹配的函数,那么就会使用函数模板。

template<classT1,classT2>T2Add(constT1&x,constT2&y){return(x+y);}doubleAdd(constintx,constdoubley){returnx+y;}intmain(){cout<<Add(1,2.2)<<endl;return0;}

3.函数模板不会类型转化,而普通函数会类型转化。

5.2 类模板

格式: template<typename T1,typename T2,……,typename Tn> class 类名 { //类内成员定义 }

类模板实例化:需要用<>指定类型。

template<classT>classStack{public:Stack(intn=4){_arr=newT[n];_size=0;_capacity=n;}~Stack(){delete[]_arr;_arr=nullptr;_size=_capacity=0;}private:T*_arr;int_size;int_capacity;};intmain(){Stack<int>s1;Stack<char>s2;}
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/29 6:54:02

自媒体工具怎么选?从功能、价格、安全性三个维度对比

当下自媒体运营早已离不开各类辅助工具&#xff0c;涵盖文案创作、视频剪辑、账号分发、数据分析等多个品类。市面上工具数量繁杂、质量参差不齐&#xff0c;很多创作者盲目选购会员&#xff0c;不仅增加运营成本&#xff0c;还可能因工具不安全导致账号限流、封禁、信息泄露。…

作者头像 李华
网站建设 2026/8/29 6:54:01

【PYTHON】模拟请求接口

【PYTHON】模拟请求接口1. 如果是请求https&#xff0c;请加上verifyFalse2. header中的中横线问题&#xff0c;需要修改为数字键盘上的-&#xff0c;否则会报错3. 请求代码4. verify设置本地证书1. 如果是请求https&#xff0c;请加上verifyFalse 2. header中的中横线问题&am…

作者头像 李华
网站建设 2026/8/29 6:51:12

ROS2机器人建模仿真实战:从URDF到Gazebo的完整链路

简介&#xff1a;机器人操作系统&#xff08;ROS2&#xff09;是智能机器人开发的核心框架&#xff0c;而建模仿真则是验证算法与系统设计的关键环节。URDF作为描述机器人几何与关节关系的标准格式&#xff0c;配合xacro宏定义实现参数化建模&#xff0c;Gazebo物理引擎则通过插…

作者头像 李华
网站建设 2026/8/29 6:46:30

MySQL安装与Navicat连接指南:破解版风险与免费替代方案

如果你最近刚好准备学 MySQL&#xff0c;大概率会遇到一个尴尬的处境&#xff1a;网上搜 MySQL 安装教程&#xff0c;版本新旧不一&#xff1b;跟着步骤装好了&#xff0c;又不知道该用什么工具去看数据&#xff1b;想让操作更省事&#xff0c;于是去搜 Navicat 下载安装&#…

作者头像 李华
网站建设 2026/8/29 6:43:05

数学建模竞赛中MATLAB微分方程符号解实战:从dsolve使用到论文写作

1. 项目概述&#xff1a;微分方程符号解在数学建模中的核心地位如果你正在准备数学建模竞赛&#xff0c;无论是国赛、美赛还是亚太杯&#xff0c;有一个工具和一类问题你几乎无法绕开&#xff1a;那就是MATLAB&#xff0c;以及如何用它来求解微分方程&#xff0c;特别是寻找其符…

作者头像 李华
网站建设 2026/8/29 6:41:25

WinForm集成PaddleOCR v3:ONNX Runtime C#部署实战

简介&#xff1a;OCR&#xff08;光学字符识别&#xff09;是一种将图像中文字转换为可编辑文本的关键技术&#xff0c;其核心依赖于检测、识别与方向分类等多阶段深度学习模型协同工作。在桌面端应用中&#xff0c;WinForm凭借稳定性和低资源占用成为政务、金融等国产化场景的…

作者头像 李华