C++ 指针与引用的区别
概念与本质
在 C++ 中,指针是一个变量,保存的是对象的地址,可以为 null,并且可以重新指向不同的对象。与之相比,引用是对象的别名,一旦绑定后就不可改变,没有独立的存储地址。
理解这两者的核心要点是:指针的取地址、解引用、以及空指针的可能性;引用是对已有对象的别名,底层通常实现为指向对象的指针但语义上更像是对象本身的别名。
语法与使用场景
声明指针使用星号,例如 int* p,可以指向一个整型变量或动态分配的对象;解引用操作符 (*) 可以访问指针指向的对象。
引用的声明紧随对象,例如 int& r = x,它必须在初始化时绑定到一个已有对象,不能为 null,常用于函数参数传递的别名、避免拷贝造成的开销。
int a = 5;
int* p = &a; // 指针
int& r = a; // 引用
*p = 10; // 通过指针修改对象
r = 20; // 通过引用修改对象
内存管理角度的差异
指针需要关注 所有权与生命周期,如果使用不当,容易产生空悬指针、野指针和内存泄漏。为了避免这些问题,常结合 RAII、智能指针等技术。
引用具有更强的语义安全性:不可为空的绑定与不可重新绑定的特性,降低了某些错误发生的概率,但也意味着对对象生命周期的依赖性更强。
内存管理基础面试题详解
动态内存与栈/堆的区别
栈内存分配由编译器管理,速度快、自动释放,但容量有限;堆内存通过 new 和 delete 手动管理,能处理更大对象但需要关注 内存分配与释放的匹配。
在面试中,常问到如何避免内存泄漏、如何检测悬空指针,以及如何使用智能指针来简化管理。
int* arr = new int[10]; // 堆内存
// 使用后要显式释放
delete[] arr;
拷贝语义与移动语义
拷贝构造函数和复制赋值运算符决定对象被如何复制,深拷贝通常需要显式实现,否则会造成资源多次释放的问题。
C++11 引入移动构造与移动赋值,资源拥有权的转移可以避免不必要的拷贝,提高性能。
class Resource {
public:Resource(size_t n) : data(new int[n]), size(n) {}~Resource() { delete[] data; }// 拷贝构造Resource(const Resource& other) : data(new int[other.size]), size(other.size) {std::copy(other.data, other.data + size, data);}// 移动构造Resource(Resource&& other) noexcept: data(other.data), size(other.size) {other.data = nullptr;other.size = 0;}
private:int* data;size_t size;
};
智能指针与资源管理
智能指针(如 std::unique_ptr、std::shared_ptr、std::weak_ptr)是实现 RAII 的核心工具,Automatic Resource Management 的典型应用。
在设计接口时,优先使用智能指针来管理资源,避免裸指针的手动 delete,降低内存泄漏与悬空指针的风险。
#include std::unique_ptr p1(new int(42)); // 独占所有权
std::shared_ptr p2 = std::make_shared(99); // 共享所有权
常见面试题型与答题要点
常见题目包括:如何在函数参数中选择使用指针还是引用?如何判断指针是否为空?如何正确实现拷贝/移动语义?

关键考点包括:指针的空值检测、引用的初始化要求、资源的所有权搬移、以及智能指针的使用场景。


