0117、安全开发篇(三):引用与内存管理
返回:C++ 面向对象基础目录 · 安全开发总目录
这一章从 C 的指针过渡到 C++ 的引用和资源管理。引用让参数传递更自然,new/delete 让对象生命周期更灵活,智能指针则是后面写安全 C++ 代码时应该优先考虑的工具。
2.0 指针与引用
引用可以理解成对象的别名。它不像指针那样保存一个可以随时改的地址,而是初始化后绑定到某个对象。
| 对比 | 指针 | 引用 |
|---|---|---|
| 是否可为空 | 可以为空 | 正常引用不应为空 |
| 是否可改指向 | 可以 | 初始化后不能改绑 |
| 使用语法 | *p / p-> |
像普通变量一样 |
| 适合场景 | 可选对象、动态对象、数组遍历 | 参数传递、别名、返回对象 |
2.1 引用基本特性
引用必须初始化,之后它就是原对象的另一个名字。
1 |
|
复盘重点:修改引用就是修改原对象。
2.2 引用作函数参数
引用参数避免复制,也能让函数修改外部对象。只读参数要加 const,表达“不修改”。
1 |
|
| 写法 | 适合场景 |
|---|---|
T value |
小对象、需要复制 |
T &value |
需要修改外部对象 |
const T &value |
大对象只读传递 |
2.3 引用作返回值
引用返回值必须指向仍然存在的对象。不能返回局部变量引用。
1 |
|
错误思路:
1 | int &bad() { |
局部变量在函数返回后销毁,返回它的引用会形成悬空引用。
2.4 常量引用特性
常量引用可以绑定临时对象,也可以避免复制。C++ 里函数参数常见写法是 const T &。
1 | void show(const std::string &text) { |
安全复盘:只读接口尽量写成 const,这样对象不会被函数悄悄改掉。
2.5 引用、常量引用与指针
如果参数必须存在,用引用;如果参数可以不存在,用指针并检查空;如果只读,用 const。
| 需求 | 推荐 |
|---|---|
| 必须传入并修改 | T & |
| 必须传入但不修改 | const T & |
| 可以不传 | T * 或智能指针 |
| 动态共享所有权 | std::shared_ptr<T> |
| 独占所有权 | std::unique_ptr<T> |
2.6 数组引用样式
数组引用可以保留数组长度。
1 |
|
这比只传 int * 更安全,因为长度没有丢。
2.7 内存分区
C++ 对象也要落在具体内存区域里。
| 区域 | 内容 |
|---|---|
| 栈区 | 局部对象,自动构造析构 |
| 堆区 | new 创建对象,需要释放或交给智能指针 |
| 全局/静态区 | 全局对象、静态对象 |
| 只读区 | 字符串字面量、常量数据 |
| 代码区 | 成员函数和普通函数机器码 |
2.8 new 与 delete
new 会分配内存并调用构造函数;delete 会调用析构函数并释放内存。
1 |
|
复盘重点:new[] 对应 delete[],new 对应 delete,不能混用。
2.9 内存异常处理
内存申请可能失败,构造函数也可能抛异常。现代 C++ 更推荐 RAII 和智能指针,让资源自动释放。
3.0 shared_ptr
std::shared_ptr 通过引用计数共享对象所有权。适合多个对象共同持有同一资源,但要警惕循环引用。
1 |
|
3.1 unique_ptr
std::unique_ptr 表示独占所有权,不能复制,只能移动。它适合表达“这个资源只有我负责”。
1 |
|
本章复盘重点
| 方向 | 问题 |
|---|---|
| 引用 | 是否会产生悬空引用 |
| 指针 | 是否为空,是否越界,是否已经释放 |
| 堆对象 | 谁负责释放 |
| 智能指针 | 所有权是独占还是共享 |
| 安全边界 | 是否能避免裸指针和手动释放 |
学习检查清单
| 检查项 | 状态 |
|---|---|
| 能区分指针和引用的使用场景 | 待复盘 |
| 能写出引用参数和常量引用参数 | 待复盘 |
| 能说明为什么不能返回局部变量引用 | 待复盘 |
能正确配对 new/delete 和 new[]/delete[] |
待复盘 |
能说明 unique_ptr 和 shared_ptr 的区别 |
待复盘 |
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Ruiqy~!






