对象先于地址
指针保存地址,但地址有效不等于对应对象仍然存在。理解指针需要同时考虑对象类型、存储范围、生命周期和所有者。返回局部变量的地址会留下悬空指针;数组下标越界即使没有马上崩溃,也不能当作正确行为。
C 需要明确安排资源取得与释放的路径。C++ 可以用 RAII 把资源生命周期绑定到对象,作用域结束时执行析构。资源不只包括内存,也包括文件、锁和设备句柄。
#include <memory>
#include <vector>
int main() {
auto value = std::make_unique<int>(7);
std::vector<int> samples{1, 2, 3};
return *value == 7 && samples.at(1) == 2 ? 0 : 1;
}
示例需要支持 C++14 或更新标准的编译器。unique_ptr 表达唯一所有权;普通指针或引用常用于暂时访问对象。只有确有共享所有权时才使用 shared_ptr,并识别循环引用。使用智能指针仍需避免把内部裸指针保存到超出对象生命周期的位置。
值、引用与移动
按值传递会构造参数对象;引用可以避免复制,但被引用对象必须存活。移动允许转移资源,并不自动保证所有类型的移动都便宜。const 限制通过当前访问路径进行的修改,不是多线程同步机制。
容器扩容可能让已有指针、引用或迭代器失效。硬件寄存器访问还需要阅读芯片文档;volatile 不能代替线程原子操作、内存屏障或锁。
练习与面试自查
分别构造“返回局部地址”和“vector 扩容后继续使用旧引用”的错误,在独立练习工程中用编译告警、AddressSanitizer 或调试器定位。再用所有权明确的接口改写。
解释 RAII 如何处理提前返回与异常路径,以及所有权、生命周期和线程安全为什么是三个不同的问题。本文代码是语言语义示例,真实嵌入式构建还要适配目标工具链与运行库。