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

c/c++内存管理和模板

(一)C/C++内存管理

一,c语言动态内存管理

C 语言的动态内存管理是对堆内存的手动分配,使用与释放过程,堆内存提供了灵活的大小控制,但需要开发者完全负责其生命周期管理。所有动态内存函数都定义在<stdlib.h>头文件中,返回值均为void*类型,需要强制转换为具体类型使用。

1,malloc:申请未初始化的内存

void* malloc(size_t size);

向堆区申请size字节的连续内存空间,size是需要申请的内存字节数,申请成功返回指向申请内存起始地址的void*指针,需要强制转换为具体类型使用;申请失败返回NULL。申请的内存不会被初始化,内容是随机值。

2,calloc:申请并初始化内存

void* calloc(size_t size, size_t size);

向堆区申请num个大小为size字节的连续内存空间,num是元素个数,size是每个元素的字节数,返回值同malloc,申请的内存会被自动初始化为 0,这是与malloc的主要区别。

3,realloc:调整已申请内存的大小

void* realloc(void* ptr, size_t newSize);

调整ptr指向的动态内存的大小为newSize字节,ptr是之前动态开辟的空间指针,newSize是调整后的新大小(字节)。申请成功返回指向调整后内存的指针,申请分为两种情况(原地扩容和异地扩容),原地扩容是原内存后面有足够的连续空间,直接在原内存基础上扩展,返回原指针;异地扩容是原内存后面没有足够空间,重新申请一块新的更大内存,将原数据复制过去,释放原内存,返回新指针(找到新空间,拷贝旧数据,释放旧空间)。申请失败,则返回NULL,原内存保持不变。如果ptrNULL,则realloc等价于malloc(newSize)。

二,c++的动态内存管理

1,内置数据类型的动态分配

int* ptr1 = (int*)malloc(5 * sizeof(int));//不能初始化 int* ptr2 = new int[5] {5, 4, 3, 2, 1}; //可以初始化 free(ptr1); ptr1 = nullptr; delete[] ptr2; ptr2 = nullptr;

分配数组用new 类型[大小],释放必须用delete[]。若用delete释放数组,只会调用第一个元素的析构函数,导致内存泄漏new[]会额外存储数组的大小信息,delete[]会根据这个信息调用所有元素的析构函数。如果申请空间失败,就会抛出异常,就不用自己去判断分配空间是否成功了。

2,自定义类型的动态分配

class A{ public: A(int a) :_a(a){ cout << "A(int a)" << endl; } ~A(){ cout << "~A()" << endl; } private: int _a; }; int main(){ A* p1 = (A*)malloc(5 * sizeof(A)); free(p1); p1 = NULL; A* p2 = new A[5]{ 1,2,3,4,5 }; delete[] p2; return 0; }

在申请自定义类型的空间时,new会调用构造函数,delete会调用析构函数,在以上代码中,new 会调用五次构造函数,并初始化,delete会调用五次析构函数。而malloc和free不会调用。

(二)template(模板)

一,函数模板

1,单个模板参数

函数模板是 C++泛型编程的核心工具,允许你编写与类型无关的通用代码,编译器会根据调用时的实际类型自动生成对应的函数版本,极大地减少了代码重复,同时保持了类型安全。函数模板完美解决了这些问题:一份代码,适配所有类型,且编译期进行类型检查。

template<typename T> void Swap(T& x1, T& x2){ T tmp = x1; x1 = x2; x2 = tmp; } int main(){ int i = 3; int j = 7; cout << "交换前" << i << " " << j << endl;//3 7 Swap(i, j); cout << "交换后" << i << " " << j << endl;//7 3 double d1 = 3.5; double d2 = 1.89; cout << "交换前" << d1 << " " << d2 << endl;//3.5 1.89 Swap(d1, d2); cout << "交换后" << d1 << " " << d2 << endl;//1.89 3.5 return 0; }

这样我们就不用再写多个交换函数了。

2,多个模板参数

调用时,参数可以是多种类型。

template<class T1,class T2,class T3> double Arithmetic(const T1& x1,const T2& x2,const T3& x3){ return x1 + x2 + x3; } int main() { cout << Arithmetic(1, 3.4, 1.256) << endl; cout << Arithmetic(1, 3, 5) << endl; cout << Arithmetic(2.19, 3.4, 1.256) << endl; return 0; }

二,类模板

以下是实现了一个栈的类模板:

#include<iostream> #include<assert.h> using namespace std; namespace zS{ template<class SDatatype> class stack{ public: stack(int n = 4) :_arr(new SDatatype[n]) , _size(0) , _capacity(n) { } void ExpandCapacity(); void Push(SDatatype x); SDatatype stacktop()const; void stackPop(); bool Empty()const; int stackSize()const; ~stack(){ delete[] _arr; this->_size = _capacity = 0; } private: SDatatype* _arr; int _size; int _capacity; }; } template<class SDatatype> void zS::stack<SDatatype>::ExpandCapacity(){ SDatatype* NewCapa = new SDatatype[this->_capacity * 2]; memcpy(NewCapa, this->_arr, this->_capacity * sizeof(SDatatype)); delete[] _arr; _arr = NewCapa; this->_capacity *= 2; } template<class SDatatype> void zS::stack<SDatatype>::Push(SDatatype x){ if (this->_size == _capacity) { ExpandCapacity(); } this->_arr[_size++] = x; } template<class SDatatype> bool zS::stack<SDatatype>::Empty()const{ return _size == 0; } template<class SDatatype> SDatatype zS::stack<SDatatype>::stacktop()const{ assert(!Empty()); return _arr[_size - 1]; } template<class SDatatype> void zS::stack<SDatatype>::stackPop(){ assert(!Empty()); --this->_size; } template<class SDatatype> int zS::stack<SDatatype>::stackSize()const{ return this->_size; }
http://www.jsqmd.com/news/930251/

相关文章:

  • 题解:AtCoder AT_awc0080_d Network Construction
  • Arduino声控小车制作指南:从硬件搭建到代码优化的完整实践
  • 最新高效的AI浏览器企业3个核心维度深度横评 - 速递信息
  • 2026永康木门品牌优选,这几家品质靠谱
  • WindowResizer终极指南:深度解析Windows窗口强制调整技术实现原理
  • 南京防水补漏哪家靠谱?2026本地专业防水品牌测评避坑指南 - 吉修匠
  • 量化训练时 fusebn/withbn 简介
  • R.E.P.O. Modding Wiki 中文翻译完成 - 让国内 Mod 开发者也能轻松上手
  • ShawzinBot:MIDI到游戏乐器自动化演奏的跨领域技术融合实践
  • LanzouAPI技术深度解析:云存储直链提取与自动化下载架构设计
  • 如何一次性解决Windows C++运行库问题:VisualCppRedist AIO终极指南
  • 终极SPT-AKI存档编辑器:简单三步掌握离线版塔科夫角色编辑技巧
  • [手写系列]从零到一:Github开源你的第一个项目
  • 废旧光驱改造激光雕刻机:Arduino与A4988驱动CNC制作全攻略
  • Unity3D书页卷曲效果:终极指南与完整实现方案
  • 2026年实测10款降AI率平台推荐:免费与付费全对比,毕业论文淡化AIGC痕迹必看 - 降AI小能手
  • STM32F407驱动TB6612电机模块避坑指南:从静电防护、PWM频率到PCB走线,一个都不能少
  • 跟踪你的机器学习实验
  • 3分钟掌握ChanlunX:零基础实现缠论自动化分析的终极方案
  • 终极raylib游戏开发指南:简单快速构建跨平台游戏的完整教程
  • 英雄联盟Akari助手:3步搞定智能游戏自动化,免费提升你的游戏效率
  • 陌生人之间的防备心理、社交壁垒、阶层差异。
  • AI赋能Linux Shell:自然语言交互与智能命令生成实践
  • MAA明日方舟助手:智能自动化解放玩家双手的技术实现
  • 解密PyMobileDevice3:用Python掌控iOS设备的终极武器
  • 基于树莓派与Flask的智能安防监控机器人全栈开发实战
  • 如何在5分钟内快速制作专业PPT:免费网页版演示文稿工具终极指南
  • Windows Defender终极掌控方案:开源defender-control深度剖析与技术实现
  • 证件照换底色怎么弄?2026方法、软件和在线工具保姆级教程 - 软件小管家
  • UI-TARS桌面应用:5步实现视觉语言模型驱动的GUI自动化革命