当前位置: 首页 > 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.zskr.cn/news/1441582.html

相关文章:

  • 2026永康木门品牌优选,这几家品质靠谱
  • 量化训练时 fusebn/withbn 简介
  • R.E.P.O. Modding Wiki 中文翻译完成 - 让国内 Mod 开发者也能轻松上手
  • 终极SPT-AKI存档编辑器:简单三步掌握离线版塔科夫角色编辑技巧
  • STM32F407驱动TB6612电机模块避坑指南:从静电防护、PWM频率到PCB走线,一个都不能少
  • 3分钟掌握ChanlunX:零基础实现缠论自动化分析的终极方案
  • 英雄联盟Akari助手:3步搞定智能游戏自动化,免费提升你的游戏效率
  • 陌生人之间的防备心理、社交壁垒、阶层差异。
  • 证件照换底色怎么弄?2026方法、软件和在线工具保姆级教程 - 软件小管家
  • 鄂州各区黄金回收怎么选?福满多黄金回收24小时免费上门变现 - 余生黄金回收
  • 终极游戏开发革命:raylib如何用50行代码重塑你的界面编程体验?
  • 告别‘元素不可见’:Selenium+Pytest处理shadow-root的完整避坑指南
  • 基于HC-12与Arduino的远距离无线通信系统搭建指南
  • STM32小车主控工程:支持思岚雷达、自动回充与多传感器避障(IAR环境)
  • 多功能的AI浏览器平台排名:2026年实力盘点 - 速递信息
  • java matches Java匹配上瘾?这编程语言让你从菜鸟秒变大神
  • QuickBMS:游戏资源逆向工程的终极瑞士军刀 [特殊字符]
  • 终极QQ空间数据备份指南:如何用Python快速保存你的青春记忆
  • Zend 引擎执行优先级的庖丁解牛
  • 如何快速配置游戏助手:终极自动化解决方案
  • 为什么你的Windows字体看起来总是不如Mac清晰?3步解决法来了
  • Sora 2文件大小波动超±15%?用这1个Python校验脚本+2行FFmpeg重封装指令,强制锁定目标KB值
  • MySQL 三大日志:Redo Log、Undo Log 和 Binlog 完全解析
  • Avidemux2终极指南:5分钟掌握开源视频编辑神器
  • 高速电路地线并非越粗越好,背后原理你了解吗?
  • STM32F103用ADC采样+LCD实时画波形,开箱即用工程包
  • 东莞家庭除臭虫全攻略:轻松告别烦人小虫,安心居住每刻 - 品牌优选官
  • 【限时解禁】Sora 2内部法线生成管线首次公开:含3类不可见约束条件、4层微分渲染校准机制与1套评估基准
  • OpenUtau完全指南:免费开源虚拟歌手软件,让音乐创作触手可及
  • 基于MQTT与Node-RED的工业PLC与智能家居系统集成实践