引用必须初始化且不可重绑定,指针可为空或后期赋值;sizeof和typeid对引用返回所引类型的属性,指针则返回地址相关属性;引用传参避免拷贝但非const引用不接受临时量。

引用必须初始化,指针可以为空
引用在定义时就必须绑定到一个已存在的对象,之后不能再改绑;而指针可以先声明,后赋值,也可以一直不指向任何对象(即为 nullptr)。这是最基础也最容易踩坑的一点:试图使用未初始化的引用会导致编译错误,但未初始化的指针可能只是悬空,运行时才出问题。
-
int x = 42; int& r = x;✅ 合法,r是x的别名 -
int& r;❌ 编译失败:引用必须初始化 -
int* p;✅ 合法,p是未初始化的指针(值不确定) -
int* p = nullptr;✅ 明确置空,安全可判
引用不能重新绑定,指针可以随时改指向
引用一旦初始化,就永远代表那个对象,没有“重新赋值为另一个对象的引用”这回事;而指针变量本身的值(即地址)可以多次修改。很多人误以为 r = y; 是让 r 指向 y,其实这只是给 r 所绑定的对象(即 x)赋值为 y 的值。
int x = 10, y = 20; int& r = x; r = y; // 等价于 x = y; → x 变成 20,r 仍绑定 x int* p = &x; p = &y; // ✅ p 现在指向 y,和之前完全无关
sizeof 和 typeid 行为不同
sizeof 对引用返回的是所引用类型的大小,不是“引用头”的大小;而指针的 sizeof 总是返回地址宽度(如 64 位系统通常是 8)。同样,typeid 对引用返回的是所引用类型的类型信息,不是“引用类型”本身。
-
int x; int& r = x;→sizeof(r)是sizeof(int),不是 8 -
int* p;→sizeof(p)是平台指针大小(通常 4 或 8) -
typeid(r).name()和typeid(x).name()一致;typeid(p).name()是int*
函数参数传递中,引用避免拷贝但不改变语义
用引用传参(尤其是 const T&)能避免大对象拷贝,又保持调用端语法简洁;而指针传参需要显式取地址(&obj),且调用方得承担空指针检查责任。但要注意:非 const 引用参数强制要求传入左值,这点常被忽略。
立即学习“C++免费学习笔记(深入)”;
void f(const std::string& s) { /* 安全读取 */ }
void g(std::string* s) { /* 必须检查 s != nullptr */ }
std::string s = "hello";
f(s); // ✅
f("abc"); // ✅ 字符串字面量隐式转为 const std::string&
g(&s); // ✅
g(nullptr); // ❌ 危险,且调用写法暴露实现细节
真正容易被忽略的是:void h(int& x) 无法接受字面量或临时量(如 h(42) 编译失败),而 const int& 可以——这不是语法糖,是语言对生命周期延长的特殊保证。









