指针是 C 的招牌,引用是 C++ 对指针的"安全升级"。两者都能间接访问变量,但语义大不相同:指针是"存地址的变量",引用是"变量的别名"。理解它们的区别,是写出正确 C++ 的分水岭。

1. 引用是什么

引用必须在声明时初始化,之后永远绑定同一个对象,不能"改绑"。它本质上是编译器帮你隐藏了取址和解引用:

int x = 10;
int& r = x;      // r 是 x 的别名
r = 20;          // x 变成 20
int y = 99;
r = y;           // 注意:这是把 y 的值赋给 x,不是让 r 改绑 y!

2. 引用 vs 指针:一张表看懂

对比项引用指针
初始化必须立即绑定对象可以不初始化(野指针危险)
改绑不允许可指向别处
空值不存在"空引用"可为 nullptr
运算无指针算术支持 ++、+n 等
解引用直接当变量用需 *p 或 ->
适用函数参数/返回值、遍历动态内存、容器、可选对象

3. const 引用:只读 + 省拷贝

传大对象时,值传递会拷贝整个对象;传引用只传地址。加 const 承诺不修改,还能接受临时量:

void print(const string& s) {
    // 只读访问,不拷贝,s 很大也不怕
    cout << s << endl;
}

print("hello");   // 临时字符串也能绑定 const 引用

口诀:参数优先 const 引用;需要修改才用普通引用;内置小类型(如 int)直接值传递即可。

4. 引用作返回值

返回引用可以避免拷贝,也能实现链式调用(cout << a << b 就是这么干的)。但绝不能返回局部变量的引用——函数结束局部变量就销毁了:

int& bad() {
    int local = 42;
    return local;   // 悬垂引用!UB
}

vector<int> v = {1, 2, 3};
int& good = v[0];  // 引用容器里的元素,合法
good = 100;        // v[0] 变成 100

5. 指针仍不可替代的场景

6. 现代 C++ 的实践建议

void process(Widget& w);            // 必须修改 → 引用
void dump(const Widget& w);         // 只读 → const 引用
Widget* find(int id);               // 可能找不到 → 返回指针(nullptr)
unique_ptr<Widget> make();          // 拥有所有权 → 智能指针
Widget w; Widget* p = &w;           // 需要数组/多态 → 原始指针
💡 一句话记忆:"能用引用就别用指针,能用 const 引用就别用普通引用"。把"传参用引用、拥有用智能指针、可选用裸指针"当成默认习惯,你的代码会安全一大截。