内部对象 II
约 1038 个字 194 行代码 预计阅读时间 11 分钟
对象内部机制进阶
本章深入探讨C++对象的高级内部机制,重点关注引用、常量及动态内存分配。这些概念是高效C++编程的基础。
引用
-
引用基础
引用是C++中操作对象的新方式,本质上是对象的别名:
- 引用必须在定义时用变量初始化
- 初始化建立绑定,之后不能更改
- 引用的目标必须有位置(左值)
特性 引用 指针 可为空 否 是 依赖现有变量 是 否 可更改指向 否 是 使用方式 直接使用 需解引用 初始化 必须初始化 可以不初始化 -
左值与右值
- 左值:可出现在赋值表达式左侧,有地址、有名字
- 包括变量、引用
-
解引用、数组下标、点操作符、箭头操作符的结果
-
右值:只能出现在赋值表达式右侧,无地址或无名
- 包括字面量、表达式的临时结果
C++11中,右值分为两类:
- 纯右值(prvalue):传统C++中的右值概念
- 临时变量(如函数返回的非引用值)
- 运算表达式(如1+3)产生的值
- 字面量(如2、'c'、true)
-
类型转换结果、lambda表达式
-
将亡值(xvalue):与右值引用相关的表达式
- 将要被移动的对象
- 返回右值引用T&&的函数返回值
- std::move的返回值
-
右值引用应用
可以基于参数是左值还是右值进行重载:
右值引用可以延长临时对象的生命周期:
- ReturnRvalue函数返回的右值通常在表达式结束后生命终结
- 通过右值引用,该右值"重获新生"
- 右值生命期将与引用变量a的生命期一样
- 比普通拷贝少一次构造和析构开销
将左值转换为右值引用,用于支持移动语义:
#include <utility> std::vector<int> createVector() { std::vector<int> result = {1, 2, 3, 4, 5}; return std::move(result); // 显式移动,避免拷贝 } // 在移动构造函数中使用 MyClass(MyClass&& other) noexcept : resource(std::move(other.resource)) { other.resource = nullptr; // 资源已转移,源对象置空 }
注意:移动操作会改变源对象的状态,使用后源对象通常处于"有效但未指定"状态
常量
-
常量基础
常量是不可修改的变量:
- 常量遵循作用域规则
- C++中的const默认为内部链接
- 编译器尽量避免为const分配存储空间
- 使用
extern
可强制分配存储空间
-
指针与常量
两种不同的概念:
解读复杂声明的技巧:
-
常量与类
不能修改类的状态:
只能调用常量成员函数:
-
函数与常量
对于值返回,const通常也没有太大意义:
动态内存分配
动态分配内存是C++的重要特性:
使用new/delete的注意事项:
- 不要用delete释放非new分配的内存
- 不要重复释放同一块内存
- 用new[ ]分配的数组必须用delete[ ]释放
- 用new分配的单个对象必须用delete释放
- 对空指针使用delete是安全的(无操作)
现代C++内存管理
在现代C++(C++11及以后)中,建议使用智能指针而非裸指针管理动态内存:
#include <memory>
// unique_ptr:独占所有权
std::unique_ptr<int> p1(new int(42));
auto p2 = std::make_unique<int>(100); // C++14
// shared_ptr:共享所有权
std::shared_ptr<int> p3 = std::make_shared<int>(100);
std::shared_ptr<int> p4 = p3; // p3和p4共享所有权
// 使用时无需手动释放内存
智能指针能够自动管理内存生命周期,有效避免内存泄漏和悬挂指针等问题。