C++--内存管理

C/C++ 内存管理完全指南

一篇帮你彻底搞懂 C/C++ 内存管理的复习笔记


一、C/C++ 内存分布

1.1 内存区域划分

复制代码
┌─────────────────────────────────────┐  高地址
│              栈区 (Stack)           │  ↓ 向下增长
│         非静态局部变量/函数参数        │
├─────────────────────────────────────┤
│            内存映射段                │
│      (共享库、进程间通信)             │
├─────────────────────────────────────┤
│              堆区 (Heap)            │  ↑ 向上增长
│         动态内存分配                 │
├─────────────────────────────────────┤
│           数据段(静态区)              │
│        全局变量/静态变量              │
├─────────────────────────────────────┤
│           代码段(常量区)              │
│        可执行代码/只读常量            │
└─────────────────────────────────────┘  低地址

1.2 经典例题

cpp 复制代码
int globalVar = 1;
static int staticGlobalVar = 1;

void Test() {
    static int staticVar = 1;
    int localVar = 1;
    int num1[10] = { 1, 2, 3, 4 };
    char char2[] = "abcd";
    const char* pChar3 = "abcd";
    int* ptr1 = (int*)malloc(sizeof(int) * 4);
    int* ptr2 = (int*)calloc(4, sizeof(int));
    int* ptr3 = (int*)realloc(ptr2, sizeof(int) * 4);
    free(ptr1);
    free(ptr3);
}

1.3 变量存储位置速查表

变量 存储位置 说明
globalVar C. 数据段 全局变量
staticGlobalVar C. 数据段 静态全局变量
staticVar C. 数据段 静态局部变量
localVar A. 栈 局部变量
num1 A. 栈 局部数组
char2 A. 栈 局部数组
*char2 A. 栈 数组元素在栈上
pChar3 A. 栈 指针变量本身在栈上
*pChar3 D. 代码段 指向的字符串常量
ptr1 A. 栈 指针变量本身在栈上
*ptr1 B. 堆 指向的动态内存

二、C语言动态内存管理

2.1 三大函数对比

函数 功能 是否初始化 返回值
malloc 分配指定字节数 ❌ 不初始化 void*
calloc 分配n个size字节 ✅ 初始化为0 void*
realloc 调整已分配内存 保留原数据 void*

2.2 使用示例

cpp 复制代码
int* p1 = (int*)malloc(sizeof(int) * 4);     // 分配16字节,不初始化
int* p2 = (int*)calloc(4, sizeof(int));       // 分配16字节,初始化为0
int* p3 = (int*)realloc(p2, sizeof(int) * 10); // 扩展到40字节

free(p1);
free(p3);  // 注意:p2已被realloc,只需free(p3)

2.3 【面试题】malloc/calloc/realloc的区别

复制代码
malloc:只分配空间,不初始化,内容随机
calloc:分配空间并初始化为0
realloc:调整已有内存大小,保留原数据

三、C++ 内存管理:new/delete

3.1 内置类型

cpp 复制代码
void Test() {
    // 动态申请一个int类型的空间
    int* ptr4 = new int;

    // 动态申请一个int类型的空间并初始化为10
    int* ptr5 = new int(10);

    // 动态申请3个int类型的空间
    int* ptr6 = new int[3];

    delete ptr4;      // 释放单个
    delete ptr5;      // 释放单个
    delete[] ptr6;    // 释放数组,必须用 delete[]
}

⚠️ 注意newdeletenew[]delete[] 必须匹配使用!

3.2 自定义类型

cpp 复制代码
class A {
public:
    A(int a = 0) : _a(a) {
        cout << "A():" << this << endl;
    }
    ~A() {
        cout << "~A():" << this << endl;
    }
private:
    int _a;
};

int main() {
    // malloc/free:只开空间,不调用构造/析构
    A* p1 = (A*)malloc(sizeof(A));
    free(p1);

    // new/delete:开空间 + 调用构造/析构
    A* p2 = new A(1);    // 调用构造函数
    delete p2;           // 调用析构函数

    // 数组形式
    A* p6 = new A[10];   // 调用10次构造函数
    delete[] p6;         // 调用10次析构函数

    return 0;
}

3.3 核心区别

操作 malloc/free new/delete
自定义类型 只开空间 开空间 + 构造/析构
内置类型 基本相同 基本相同

四、operator new 与 operator delete

4.1 本质

  • newdelete操作符
  • operator newoperator delete全局函数
  • new 底层调用 operator new
  • delete 底层调用 operator delete

4.2 实现原理

cpp 复制代码
// operator new:底层就是 malloc
void* operator new(size_t size) {
    void* p;
    while ((p = malloc(size)) == 0) {
        if (_callnewh(size) == 0) {
            throw std::bad_alloc();  // 失败抛异常
        }
    }
    return p;
}

// operator delete:底层就是 free
void operator delete(void* pUserData) {
    if (pUserData == NULL) return;
    _free_dbg(pUserData, _NORMAL_BLOCK);
}

4.3 关键流程图

复制代码
new T
  │
  ├──→ operator new (申请空间)
  │         │
  │         └──→ malloc
  │                   │
  │                   ├── 成功 → 返回指针
  │                   └── 失败 → 抛异常 bad_alloc
  │
  └──→ 调用构造函数

delete p
  │
  ├──→ 调用析构函数
  │
  └──→ operator delete (释放空间)
            │
            └──→ free

五、new/delete 实现原理

5.1 内置类型

对比项 new/delete malloc/free
单元素 new / delete malloc / free
连续空间 new[] / delete[] malloc / free
失败处理 抛异常 返回 NULL

5.2 自定义类型

new 的原理:

复制代码
1. 调用 operator new 申请空间
2. 在申请的空间上执行构造函数

delete 的原理:

复制代码
1. 在空间上执行析构函数
2. 调用 operator delete 释放空间

new T[N] 的原理:

复制代码
1. 调用 operator new[] → 内部调用 operator new 申请 N 个对象空间
2. 在申请的空间上执行 N 次构造函数

delete[] 的原理:

复制代码
1. 在释放的对象空间上执行 N 次析构函数
2. 调用 operator delete[] → 内部调用 operator delete 释放空间

六、定位 new 表达式

6.1 概念

定位 new (placement-new) 用于在已分配的原始内存空间中调用构造函数初始化对象。

6.2 语法

cpp 复制代码
new (place_address) type
new (place_address) type(initializer-list)

6.3 使用场景

配合内存池使用:内存池分配的内存未初始化,需用定位 new 调用构造函数。

6.4 示例

cpp 复制代码
class A {
public:
    A(int a = 0) : _a(a) { cout << "A()" << endl; }
    ~A() { cout << "~A()" << endl; }
private:
    int _a;
};

int main() {
    // 方式一:malloc + 定位 new
    A* p1 = (A*)malloc(sizeof(A));
    new(p1)A;        // 显式调用构造函数
    p1->~A();        // 显式调用析构函数
    free(p1);

    // 方式二:operator new + 定位 new
    A* p2 = (A*)operator new(sizeof(A));
    new(p2)A(10);    // 带参数的构造函数
    p2->~A();
    operator delete(p2);

    return 0;
}

七、malloc/free vs new/delete 对比

7.1 共同点

  • 都从堆上申请空间
  • 都需要手动释放

7.2 不同点速查表

区别点 malloc/free new/delete
本质 函数 操作符
初始化 不初始化 可以初始化
空间大小 手动计算并传递 自动计算
返回值 void* (需强转) 对应类型指针
失败处理 返回 NULL (需判空) 抛异常 (需捕获)
自定义类型 只开空间 开空间 + 构造/析构

7.3 记忆口诀

复制代码
malloc 是函数要强转,new 是操作符自动算;
malloc 失败返回空,new 失败抛异常;
自定义类型 new/delete,构造析构自动调!

八、一图总结

复制代码
┌───────────────────────────────────────────────────────┐
│                  C/C++ 内存管理总结                    │
├───────────────────────────────────────────────────────┤
│                                                       │
│   【内存区域】                                         │
│      栈 → 局部变量,向下增长                          │
│      堆 → 动态分配,向上增长                          │
│      数据段 → 全局/静态变量                           │
│      代码段 → 代码/常量                               │
│                                                       │
│   【C语言方式】                                        │
│      malloc/calloc/realloc + free                    │
│                                                       │
│   【C++方式】                                         │
│      new/delete → 单个元素                            │
│      new[]/delete[] → 连续空间                        │
│                                                       │
│   【核心区别】                                         │
│      new/delete 会调用构造/析构函数                   │
│      malloc/free 不会                                 │
│                                                       │
│   【定位 new】                                         │
│      配合内存池使用,显式调用构造函数                  │
│                                                       │
└───────────────────────────────────────────────────────┘

希望这篇笔记能帮助你快速复习 C/C++ 内存管理知识!如有疑问,欢迎讨论交流。

相关推荐
Yungoal2 小时前
C++ 标准模板库STL(Standard Template Library)
c++·哈希算法·散列表
我真不是小鱼2 小时前
cpp刷题打卡记录27——无重复字符的最长子串 & 找到字符串中所有字母的异位词
数据结构·c++·算法·leetcode
一直不明飞行2 小时前
C++:string,写法s.find(‘@‘) != s.end()是否有问题
开发语言·c++·算法
CNemon2 小时前
《怎样学习文言文》溯源
学习
白緢2 小时前
嵌入式 Linux + 内核开发高频问题及排查
java·linux·运维
Proxy_ZZ02 小时前
打造自己的信道编码工具箱——Turbo、LDPC、极化码三合一
c语言·算法·信息与通信
wayz112 小时前
21天机器学习核心算法学习计划(量化方向)
学习·算法·机器学习
Flandern11112 小时前
Go程序员学习AI大模型项目实战02:给 AI 装上“大脑”:从配置解包到流式生成的深度拆解
人工智能·后端·python·学习·golang
juniperhan2 小时前
Flink 系列第4篇:Flink 时间系统与 Timer 定时器实战精讲
java·大数据·数据仓库·flink