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

C++动态内存管理 模板

动态内存管理

C++内存分区

C++程序的内存通常划分为五个主要区域,每个区域有特定用途和管理方式:

代码区(Text Segment)

  • 存放程序的机器指令,即编译后的可执行代码

  • 通常是只读的,防止指令被意外修改

  • 多个相同程序的进程可共享此区域,节省内存

栈区(Stack)

  • 存储局部变量(非static修饰)、函数参数、返回地址等

  • 由编译器自动管理内存,遵循“后进先出”(LIFO)原则

  • 内存分配和释放速度快,但空间有限(通常1MB到8MB),超出会导致栈溢出

  • 每次进入一个函数就建立一个新的栈

堆区(Heap)

  • 通过newmalloc动态分配内存,需手动释放(deletefree)

  • 生命周期由开发者控制,未释放会导致内存泄漏

  • 空间较大,但管理复杂,访问速度较栈区慢

全局/静态存储区(Global/Static Storage Area)

  • 存放全局变量、静态变量(static修饰)

  • 分为已初始化(Data段)和未初始化(BSS段)两部分

  • 生命周期为整个程序运行期间,编译时分配内存并初始化

常量存储区(Constant Storage Area)

  • 存放常量值,如字符串常量、const修饰的全局常量

  • 内存区域不可修改,防止数据被意外更改

  • 生命周期与程序相同,通常位于只读数据段

  • const不改变存储的地址,被const修饰的变量或函数并不属于常量区


new和delete操作符

C++通过new和delete操作符进行动态内存管理,示例如下
void Test() { // 动态申请一个int类型的空间并默认初始化成0 int* ptr4 = new int; // 动态申请一个int类型的空间并初始化为10 int* ptr5 = new int(10); // 动态申请10个int类型的空间并默认初始化成0 int* ptr6 = new int[10]; // 动态申请10个int类型的空间并初始化 int* ptr7 = new int[10]{1,2,3,4,5,6,7,8,9,10}; //释放申请的空间 delete ptr4; delete ptr5; delete[] ptr6;//注意这里的释放带[] }

operator new与operator delete函数

new和delete是用户进行动态内存申请和释放的操作符,而operator new 和operator delete是系统提供的全局函数new在底层调用operator new全局函数来申请空间,delete在底层通过operator delete全局函数来释放空间,operator new/operator delete和new/delete以及malloc/free的关系如下:

new的原理

1. 调用operator new函数申请空间,而operator new又是通过调用c语言的malloc来申请空间

2. 在申请的空间上执行构造函数,完成对象的构造

delete的原理

1. 在空间上执行析构函数,完成对象中资源的清理工作

2. 调用operator delete函数释放对象的空间,operator delete则是调用了


malloc/free和new/delete的区别

malloc/free和new/delete的共同点是:都是从堆上申请空间,并且需要用户手动释放。不同的地方如下:

1. malloc和free是函数,new和delete是操作符

2. malloc申请的空间不会初始化,new可以初始化

3. malloc申请空间时,需要手动计算空间大小并传递,new只需在其后跟上空间的类型即可, 如果是多个对象,[]中指定对象个数即可

4. malloc的返回值为void*, 在使用时必须强转,new不需要,因为new后跟的是空间的类型

5. malloc申请空间失败时,返回的是NULL,因此使用时必须判空,new不需要,但是new需要捕获异常

6. 申请自定义类型对象时,malloc/free只会开辟空间,不会调用构造函数与析构函数,而new在申请空间后会调用构造函数完成对象的初始化,delete在释放空间前会调用析构函数完成空间中资源的清理(最大的区别)


模板

函数模板

函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生函数的特定类型版本

函数模板格式:

template<typename T1, typename T2,......,typename Tn>

(返回值类型 函数名(参数列表){})

template<typename T>//typename也可以写成class没有影响 void Swap( T& left, T& right) { T temp = left; left = right; right = temp; }//这里的T就是不定的类型

函数模板的实例化

用不同类型的参数使用函数模板时,称为函数模板的实例化。模板参数实例化分为:隐式实例化和显式实例化。

隐式实例化:编译器根据参数类型自动推导T的类型(注意,只能根据实参的类型而不是返回值)

显式实例化:显式实例化:在函数名后的<>中指定模板参数的实际类型,一般更多的情况下使用隐式实例化,显式实例化在下面的情况下可以使用

template<class T> T Add(const T& left, const T& right) { return left + right; } int main() { int a1 = 10, a2 = 20; double d1 = 10.0, d2 = 20.0; Add(a1, d2); /* 该语句不能通过编译,当编译器看到该实例化时 通过实参a1将T推演为int,通过实参d1将T推演为double类型,但模板参数列表中只有一个T, 编译器无法确定此处到底该将T确定为int 或者 double类型而报错 注意:在推导时,编译器一般不会进行类型转换操作 */ // 此时有两种处理方式:1. 用户自己来强制转化 2. 使用显式实例化 Add(a1, (int)d1); Add<int>(a1, d1);//一开始就将T定为int return 0; }

也可以选择模板中设立多个参数解决这个问题(即仍然采用隐式实例化的方式解决)

template<class T1, class T2> T2 Add(const T1& left, const T2& right) { return left + right; } int main() { int a1 = 10, a2 = 20; double d1 = 10.0, d2 = 20.0; cout<<Add(a1, d2);//此时T1判定为int,T2判定为double(返回值就是double) return 0; }

类模板

类模板的定义格式如下:

template<class T> class fukes{ public: fukes(T a,T b):_a(a),_b(b){} void reverses(T a, T b); private: T _a; T _b; }; template<class T>//在类模板中声明和定义不宜轻易分离,因为在定义前需另外加上T的匹配 void fukes<T>::reverses(T a,T b) {//可以理解为不这么写类模板外就不知道T是什么 std::swap(a, b); } int main() { fukes<int> k(10, 20); return 0; }

类模板的实例化

类模板实例化与函数模板实例化不同,类模板实例化需要在类模板名字后跟<>,然后将实例化的类型放在<> 中即可,类模板名字不是真正的类,而实例化的结果才是真正的类,如vector才是真正的类名,vector<int>才是类型

http://www.jsqmd.com/news/983974/

相关文章:

  • GGUF+Ollama本地部署大模型:原理、选型与实战指南
  • ёRadio VU表实现原理:音频可视化效果的秘密
  • py之socket ssl双向认证代码(亲测好用)
  • GDM Settings 主题定制指南:如何更换GNOME登录界面的背景、图标和光标主题
  • 2026上海屋顶绿化十大实力服务商:五家本土品牌以生态设计与智能灌溉领跑行业深度解析 - 品牌发掘
  • 零成本AI投资分析:3步掌握智能选股系统,让小白也能获得机构级洞察
  • 3步掌握TTS-Vue:微软语音合成桌面工具零基础配置指南
  • LLMxMapReduce未来展望:多模态支持、实时处理与分布式计算的演进方向
  • 神经渲染:打开宇宙的“数字之眼”——天文可视化的新范式
  • 工厂用吸尘器排行榜2025实测:史沃斯凭什么稳居第一? - 工业清洁测评社
  • FGO-py:让你的Fate/Grand Order游戏体验焕然一新的智能管家
  • Mac文件预览革命:50+款QuickLook插件如何彻底改变你的工作效率
  • 卷积神经网络模型搭建(pytorch版)
  • 【安装】RocketMQ
  • Mac Mouse Fix终极指南:3个技巧让你的普通鼠标在Mac上超越苹果触控板体验
  • Python 爬虫项目 基于 Redis 实现爬虫 IP 代理池搭建与动态代理轮换
  • Qbot量化交易框架深度解析:从本地部署到智能策略实战验证
  • TPM2-TSS快速入门:5步搭建可信计算开发环境
  • 2026北京玻璃钢座椅定制厂家实力榜:防腐耐候技术领跑,六家本土厂商加工优势与深度解析 - 品牌发掘
  • Plates.js 最佳实践:15个提升模板开发效率的实用技巧
  • 5分钟上手YimMenu:GTA5终极免费防护与增强工具完全指南
  • Audacity音频编辑神器:3大核心功能解决你的音频处理难题
  • 从一次信息泄露事件复盘:你的邮箱密码还在这些高危网站用吗?
  • 影刀RPA新手入门完全指南
  • Runtime昇腾运行时引擎深度解析:算子调度与执行管理的核心原理
  • SSL Socket 通信与本地 Mock Server 实践指南
  • 2026上海触点润滑脂十大供应商实力榜:六家高精度导电脂技术标杆企业的差异化优势深度解析 - 品牌发掘
  • Corrective RAG与Real-Time PPO实战:重构检索-生成时序耦合
  • CodeIsland与竞争对手对比:为什么它是AI编程助手监控的终极选择 [特殊字符]
  • 纪念币真假鉴别技巧!普通人在家就能查,杜绝高仿假货 - 深鉴新闻