C++启蒙课程:第12章 类和动态内存分配
我们将迎来“内存管理大挑战”!掌握“三大铁律”,让你的对象成为健壮的超级英雄,而不是内存泄漏的麻烦制造者!
动态内存的陷阱
理解“动态披风”`new`为何会泄漏,以及“清场队”`delete`的必要性。
复制的战争
区分“共享宝藏”(浅复制)和“独享宝藏”(深复制)的区别。
高级内存控制
掌握“智能卫士”`nullptr`和“定向传送门”`placement new`。
课时一:动态内存的陷阱与析构函数
(覆盖知识点 12.1 - 12.2.1)
12.1 “动态披风” (内存泄漏)
对象(英雄)在构造时用 `new` 获得“动态披风”(堆内存)。如果析构函数中没有 `delete`,当英雄消失时,披风被留在原地,造成内存泄漏。
12.1 “清场队” (析构函数)
必须提供显式析构函数 ~Hero(),让“清场队” 🧹 在英雄消失前,先用 `delete` 回收披风。
12.2.1 `delete` vs `delete[]`
`new[]` 建造了“数组大楼”,必须用 `delete[]` 拆除整栋楼。如果错用 `delete`,只会拆除第一个房间,导致内存泄漏。
new char[5] (大楼)delete (错误)delete[] (正确)课时二:复制的战争:浅复制与深复制
(覆盖知识点 12.3.1, 12.4, 12.8)
12.3.1 “共享的宝藏” (浅复制)
默认复制(浅复制)只复制指针(藏宝图地址),导致两个对象指向“同一块”内存(同一个宝藏)。当一个对象被销毁,宝藏被释放,另一个对象就有了“ dangling pointer” (悬挂指针)。
Hero B = A; (浅复制)~HeroA() (释放宝藏)12.3 “独享的宝藏” (深复制)
必须定义**复制构造函数**。它会 `new` 一块“新内存”,并把内容复制过去。这样两个对象就有了各自“独享的宝藏”。
Hero B = A; (深复制)12.4 赋值运算符 (=)
`s3 = s1` (赋值) 和 `MyString s2 = s1;` (初始化) 不同。赋值是发生在两个“已存在”的对象之间,它必须:1. 检查自赋值 2. 释放旧内存 3. 分配新内存 4. 复制内容。
💡 互动:s3 = s1
s3 = s1📜 代码支撑:
课时三:高级内存控制与安全措施
(覆盖知识点 12.2.2, 12.6, 12.7)
成员初始化列表
这是在构造函数中初始化的首选方式。对于 `const` 成员或引用成员,这是**唯一**的方式。
ID = val; (in body): ID(val) (in list)12.6 “定向传送门” (定位 new)
`new (address) Type` 允许你在一个“预先分配好的缓冲区”(指定地址)上构造对象,它**不分配新内存**。
new Heronew (0x500) Hero编程实践与作业
是时候检验你作为“内存管理大师”的实力了!
练习 1:动态数据与析构函数 (12.1)
任务:
编写一个 DynamicData 类,其构造函数使用 `new int` 分配内存。编写必要的构造函数和**析构函数**,以确保内存被正确释放。
点击查看参考答案
练习 2:深复制(复制构造函数与赋值) (12.3, 12.4)
任务:
为 MyString 类(包含 char* str)实现**复制构造函数**和**赋值运算符**,执行深复制。
点击查看参考答案
练习 3:成员初始化列表 (12.8)
任务:
编写一个 `ConstHolder` 类,它有一个 `const int ID` 成员。演示如何使用**成员初始化列表**来正确初始化它。
点击查看参考答案
本章知识点总结与复习 (12.8)
| 核心概念 | 解释/功能 | 关键用法/示例 |
|---|---|---|
| 类与动态内存 | `new` 分配的内存必须由类管理。 | char * str; |
| 显式析构函数 | “清场队”,必须 `delete` 构造函数中 `new` 的内存。 | ~Class() { delete [] ptr; } |
| 复制构造函数 | 在**初始化**时调用,必须执行**深复制**。 | Class(const Class & obj); |
| 赋值运算符 | 在对**已存在**对象赋值时调用,必须执行深复制。 | Class & operator=(const Class &); |
| 浅复制 vs. 深复制 | 浅复制只复制指针(危险),深复制复制数据(安全)。 | str = new char[len + 1]; |
| 成员初始化列表 | 在函数体执行前初始化,`const` 成员必须使用。 | Class() : id(0) { ... } |
| `nullptr` (C++11) | 空指针的关键字,比 `0` 更安全。 | int * ptr = nullptr; |
| 定位 `new` | 在指定地址构造对象,不分配新内存。 | new (address) Type; |