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

C/C++内存管理函数模板

C语言的内存管理:

void Test()
{int* p1 = (int*)malloc(sizeof(int));  // 申请一个int类型的空间free(p1);// 1.malloc/calloc/realloc的区别是什么?int* p2 = (int*)calloc(4, sizeof(int));int* p3 = (int*)realloc(p2, sizeof(int) * 10);// 这里需要free(p2)吗?free(p3);// 不需要// 当realloc成功调整内存大小时,原内存块p2会被自动释放。
}

malloc:

1. 只负责分配内存,不初始化内存(内存中的值是随机值)
2. 参数是 “总字节数”

3.返回值的类型是void*

calloc:

1. 分配内存后,会将内存初始化为 0
2. 参数是 “元素个数” 和 “单个元素大小(单位:字节)”

3.返回值的类型是void*

realloc:

1. 用于 “扩容” 或 “缩容” 已有的动态内存
2. 若原内存块后有足够空间,直接在原地址扩展;否则会分配新内存并拷贝原数据,原内存块自动释放
3. 若这里的参数p2NULL,则等价于malloc(size)

4.返回值的类型是void*

C语言内存管理方式在C++中可以继续使用,但有些地方就无能为力,而且使用起来比较麻烦,因 此C++又提出了自己的内存管理方式:通过new和delete操作符进行动态内存管理。

void test()
{// C语言中申请空间int* p1 = (int*)malloc(sizeof(int));  // 申请一个int类型的空间int* p3 = (int*)malloc(sizeof(int) * 10);   // 申请10个int类型的空间// 释放空间free(p1);free(p3);p1 = p3 = nullptr;// C++中申请空间int* p2 = new int; // 申请一个int类型的空间// int* p2 = new int(10); // 申请一个int类型的空间,并且初始化为10int* p4 = new int[10];  // 申请10个int类型的空间// 释放空间delete p2;delete[] p4;
}

既然已经有了malloc和free,new和delete的意义何在?

1. 对于内置类型,他们的效果是一样的
2. 对于自定义类型,效果就不一样,malloc只申请空间;new申请空间+调用构造函数初始化
3. free只是释放空间,delete调用析构函数+释放空间

class A
{friend ostream& operator<<(ostream& out, const A& a);
public:A(int a = 0):_a(a){cout << "A()" << endl;}void print(){cout << _a << endl;}~A(){cout << "~A()" << endl;}
private:int _a;
};
//ostream& operator<<(ostream& out,const A& a)
//{
//	out << a._a << endl;
//	return out;
//}// 既然已经有了malloc和free,new和delete的意义何在?
// 1.对于内置类型,他们的效果是一样的
// 2.对于自定义类型,效果就不一样,malloc只申请空间;new申请空间+调用构造函数初始化
// free只是释放空间 delete调用析构函数+释放空间
int main()
{// C语言和C++在内置类型的申请空间是一样的// 对于自定义类型是不一样的A* p1 = (A*)malloc(sizeof(A));   // malloc只申请空间A* p2 = new A;                   // new申请空间+调用构造函数初始化//A* p2 = new A(2);p2->print();//cout << &p2 << endl;free(p1);                     // free只是释放空间 p1 = nullptr;delete p2;                   // delete调用析构函数+释放空间return 0;
}

   new 比起 malloc不一样的地方:1、调用构造函数初始化 ;2、失败了抛异常
delete 比起free不一样的地方:1、调用析构函数清理

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在释放空间前会调用析构函数完成空间中资源的清理

什么是内存泄漏,内存泄漏的危害

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

内存泄漏的危害:长期运行的程序出现内存泄漏,影响很大,如操作系统、后台服务等等,出现 内存泄漏会导致响应越来越慢,最终卡死。

函数模板

void Swap(int& x, int& y)
{int temp = x;x = y;y = temp;
}void Swap(double& x, double& y)
{double temp = x;x = y;y = temp;
}void Swap(char& x, char& y)
{char temp = x;x = y;y = temp;
}// ......

观察上面的代码使用函数重载虽然可以实现多种类型数据的交换,但是有一下几个不好的地方:

1. 重载的函数仅仅是类型不同,代码复用率比较低,只要有新类型出现时,就需要用户自己增加对应的函数

2. 代码的可维护性比较低,一个出错可能所有的重载均出错 。

C++的函数模板能够解决这个问题

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

函数模板格式 :

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

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

template<typename T>
void Swap(T& x, T& y)
{T temp = x;x = y;y = temp;
}int main()
{int a = 1;int b = 2;Swap(a,b);cout << "a = " << a <<" " << "b = " << b << endl;// 显式实例化//Swap<int>(a,b); 函数变为void Swap(int& x, int& y);  // T被显式指定为int,参数为int&类型double c = 1.11;double d = 2.22;Swap(c, d);cout << "c = " << c << " " << "d = " << d << endl;char e = 'a';char f = 'b';Swap(e, f);cout << "e = " << e << " " << "f = " << f << endl;return 0;
}

在编译器编译阶段,对于模板函数的使用,编译器需要根据传入的实参类型来推演生成对应类型的函数以供 调用。比如:当用int类型使用函数模板时,编译器通过对实参类型的推演,将T确定为int类型,然 后产生一份专门处理int类型的代码,对于字符类型也是如此。

template<class T>
T Add( T& x, const T& y)  // const int& 可以接收 double 类型的 c(允许隐式类型转换为 int,生成临时变量,而 const 引用可以绑定临时变量)。
{return x + y;
}int main()
{int a = 1;int b = 2;double c = 1.11;int e = (int)c;double d = 2.22;Add(a, b);Add(c, d);// (int)c是临时变量,强制类型转换产生的临时变量(右值)无法绑定到非 const 的左值引用(T&)Add(a, (int)c);  // 函数模板中参数不加 const则此句报错Add(a, e);Add<int>(a, c);  // 函数模板中参数不加 const则此句报错return 0;
}

http://www.xdnf.cn/news/1275931.html

相关文章:

  • 小明的魔法地图:迷宫探险智慧(记忆性递归)
  • 【0基础3ds Max】主工具栏介绍(下)
  • [激光原理与应用-223]:机械 - 机加厂加工机械需要2D还是3D图?
  • Python设计模式 - 装饰模式
  • 六、RuoYi-Cloud-Plus OSS文件上传配置
  • QT常用控件三
  • Qt—— 下载、工具介绍以及新建项目
  • 从0开始的中后台管理系统-5(userList页面功能实现)
  • 40.【.NET8 实战--孢子记账--从单体到微服务--转向微服务】--扩展功能--集成网关--初始化网关
  • Pytorch进阶-timm库-00快速开始
  • (三)全栈(部署)
  • 精准计算Word文档页数的PHP类
  • 数据结构-deque(双端队列)和queue(队列)区别
  • 【npm、yarn、pnpm】特点对比,按需选择
  • Java 后端性能优化实战:从 SQL 到 JVM 调优
  • 分布微服务电商订单系统Rust编码开发[上]
  • 数组练习(一)
  • vuhub drippingblues靶场攻略
  • #4:MinIO分片上传和集群部署
  • 攻击实验(ARP欺骗、MAC洪范、TCP SYN Flood攻击、DHCP欺骗、DHCP饿死)
  • 安全运维的核心
  • C语言——深入理解指针(二)
  • 【递归、搜索与回溯算法】递归算法
  • Ollama+Deepseek+Docker+RAGFlow打造自己的私人AI知识库
  • 计算机网络:超网即路由聚合一定需要连续的IP地址吗?
  • 秋招春招实习百度笔试百度管培生笔试题库百度非技术岗笔试|笔试解析和攻略|题库分享
  • RabbitMQ面试精讲 Day 19:网络调优与连接池管理
  • Spring Boot 注解详解:@RequestMapping 的多种用法
  • 十、Linux Shell脚本:流程控制语句
  • Day41--动态规划--121. 买卖股票的最佳时机,122. 买卖股票的最佳时机 II,123. 买卖股票的最佳时机 III