ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

C++ 进阶核心知识点总结:模板、内存分区、new/delete、内存池

C++ 进阶核心知识点总结:模板、内存分区、new/delete、内存池 前言本篇是 C 类与对象之后非常核心的底层内容很多考研 408、C 面试都会高频考察结合汇编、内存示意图帮你一次性吃透。 阅读对象正在学习 C准备考研 / 面试想要理解底层原理的同学一、函数模板模板实例化1. 什么是函数模板函数模板是通用函数蓝图不是真实函数。编译器根据你调用时传入的类型自动实例化生成对应类型的函数。templatetypename T void Swap(T left, T right) { T tmp left; left right; right tmp; }templatetypename T告诉编译器T 是一个类型参数代表任意类型。2. 模板实例化重点结合汇编代码int i 10, j 20; Swap(i, j); // 推导Tint编译器生成 Swapint版本 double x 10.1, y 20.2; Swap(x, y); // 推导Tdouble编译器生成 Swapdouble版本看汇编截图✅ 核心结论模板本身不生成代码调用不同类型编译器才会生成多份重载函数这个过程叫模板实例化。不同类型实例化出独立函数地址不同。模板支持类型推导不用手动写Swapint(i,j)编译器自动识别。坑点 问模板会在编译期生成几份代码 答每一种不同的类型就实例化一份函数相同类型多次调用只生成一份。来这里提问一个问题我可不可以先写一个自己的函数然后再写一个模板那么编译器优先调用自己写的还是模板呀void swap(int a,int b) { int c a; a b; b c; } templateclass T void swap(T a,T b) { T c a; a b; b c; } int main() { int a 10; int b 20; swap(a,b); return 0; }注意C 重载决议规则优先匹配非模板的普通函数只有找不到合适普通函数时才会去实例化函数模板。调用swap(a,b)实参是int正好和上面普通函数的形参完全匹配直接选普通函数模板不会被实例化举个例子你着急去买酱油一家是楼下的超市另一家是市里面的大超市楼下的超市本来就有直接买上用就好不会直接去跑上几十公里去市里买道理是一样的。二、C/C 程序内存分区对应内存分布图内存五大区域栈区Astack 存储局部变量、函数参数、数组、临时对象。特点向下生长自动申请自动释放函数出作用域自动销毁。堆区Bheap 存储malloc / calloc / realloc / new手动开辟的空间。 特点向上生长手动申请、手动释放忘记释放会内存泄漏。数据段静态区 C存储全局变量、static 静态变量全局静态、局部 static程序启动就存在程序结束才销毁。代码段常量区 D存储可执行代码、只读常量字符串只读不能修改。内核空间操作系统使用用户代码无法访问。代码逐行解析int globalVar 1; // 全局变量 → C 数据段 static int staticGlobalVar 1; // 全局静态 → C 数据段 void Test() { static int staticVar 1; // 局部static静态变量 → C 数据段只初始化一次 int localVar 1; // 局部变量 → A 栈区 int num1[10] { 1,2,3,4 }; // 局部数组 → A 栈区 char char2[] abcd; // 数组栈开辟空间把常量字符串拷贝进栈 → char2在A栈 const char* pChar3 abcd; // pChar3指针变量本身在A栈abcd字符串字面量在D常量区 int* ptr1 (int*)malloc(sizeof(int)*4); // ptr1指针变量A栈*ptr1指向B堆 int* ptr2 (int*)calloc(4, sizeof(int)); int* ptr3 (int*)realloc(ptr2, sizeof(int)*4); free(ptr1); free(ptr3); }✅ 高频考点区分char char2[]和const char* pChar3char char2[] abcd在栈上创建数组把常量区的 abcd 拷贝一份到栈数组可以修改数组内容。const char* pChar3 abcd指针存栈字符串在只读常量区不能修改*pChar3。三、C new 和 delete底层执行流程我们之前的在类的那一部分已经详细学习过了这里就是简简单单的的复习一遍1. 单个对象 new /deleteDate* p1 new Date; delete p1;执行顺序operator new底层调用 malloc在堆上开辟原始内存空间只开空间不初始化调用构造函数在刚才开辟的内存上初始化成员变量new 开堆内存 调用构造函数delete 执行顺序调用析构函数清理对象内部资源operator delete底层调用 free释放堆内存delete 调用析构函数 释放堆空间对比 C 语言 malloc/freemalloc 只开辟原始内存不会调用构造、析构这是 C new 最大区别。2. 数组 new [] /delete [] 重点容易踩坑Stack* p new Stack[10]; delete[] p;底层机制new[]开辟空间时会多开辟一块空间保存数组对象的个数图里的数字 10作用delete[]读取这个数字知道要调用多少次析构函数⚠️ 硬性规则new [] 必须搭配 delete []new 单个对象搭配 delete不能混用。 如果混用程序行为未定义大概率崩溃。示意图解释 p 指针指向第一个对象但是往前偏移 4/8 字节存放数组元素计数。delete [] 读取这个数字循环调用 10 次析构再整体释放整块堆内存。面试题为什么 new [] 和 delete [] 不能和普通 delete 混用 答普通 delete 不会读取前面计数只会调用一次析构数组多个对象没有全部析构资源泄漏释放内存时地址错误程序崩溃。四、池化技术内存池你的项目核心复试重点1. 为什么要有内存池直接频繁调用new/malloc向操作系统申请堆内存有缺点系统调用开销大频繁申请释放速度慢频繁小块内存申请造成内存碎片内存利用率下降池化思想一次性向操作系统申请一大块连续内存放到池子里面。 后续程序需要小块内存直接从池子里面拿不频繁向操作系统申请释放的时候归还到池子而不是直接还给操作系统。通俗比喻妈妈 操作系统取钱就是 malloc。 儿子频繁用钱高频申请内存每次都找妈妈取钱很麻烦。 爸爸一次性向妈妈拿 20 块钱交给儿子儿子用钱直接从这 20 块里面拿用完放回不用反复找妈妈。这就是内存池。同类池化技术内存池管理内存分配释放线程池预先创建一批线程复用线程避免频繁创建销毁线程连接池数据库连接复用2. 内存池优缺点✅ 优点减少系统调用分配内存速度更快减少内存碎片提升内存利用率❌ 缺点1.一次性预先开辟大块内存程序启动就占用内存哪怕暂时不用。全文知识点汇总函数模板模板是蓝图编译期根据调用类型实例化生成对应类型函数不同类型生成不同函数。汇编可以看到实例化后的函数符号Swapint Swapdouble。内存分区栈局部变量自动销毁向下生长堆new/malloc 手动开辟手动释放静态区全局、static 变量程序全程存在常量区字符串字面量只读new/deletenew operator newmalloc 开空间 构造函数 delete 析构函数 operator deletefree 释放 new [] 会额外保存对象数量用来 delete [] 调用多次析构new [] 和 delete [] 必须配对。内存池池化技术一次性向 OS 申请大块内存程序从池子取小块内存减少系统调用减少内存碎片适合高频申请释放内存场景。同类线程池、连接池
返回列表