回顾:普通左值引用的限制
《左值引用》中,我们指出:普通左值引用只能绑定到可修改的左值。因此以下代码非法:
int main()
{
const int x{ 5 }; // x 是不可修改的(const)左值
int& ref{ x }; // 错误:ref 无法绑定到不可修改的左值
}
若允许这种绑定,就能通过非常量引用修改 const
变量,破坏常量语义。
指向常量的左值引用
若在声明左值引用时使用 const
关键字,即可将该引用声明为指向常量的左值引用(简称“常量引用”或“const 引用”)。常量引用可以绑定到不可修改的左值:
int main()
{
const int x{ 5 };
const int& ref{ x }; // 合法:ref 是指向 const int 的引用
}
由于常量引用把被引用对象视为 const
,因此只能读取而不能修改:
#include <iostream>
int main()
{
const int x{ 5 };
const int& ref{ x };
std::cout << ref << '\n'; // OK:读取
ref = 6; // 错误:无法通过常量引用修改
}
用常量引用绑定可修改左值
常量引用同样能绑定到可修改的左值;此时,通过引用访问该对象时,它被视为 const
:
int main()
{
int x{ 5 };
const int& ref{ x }; // 合法:绑定到可修改左值 x
std::cout << ref << '\n'; // OK:读取
ref = 7; // 错误:不能通过 ref 修改
x = 6; // OK:仍可通过原标识符修改
}
最佳实践
除非需要修改被引用对象,否则应优先使用指向常量的左值引用。
用常量引用绑定右值
常量引用甚至可绑定到右值:
int main()
{
const int& ref{ 5 }; // 合法:5 是右值
std::cout << ref << '\n'; // 输出 5
}
此时编译器会创建一个临时对象并用右值初始化,常量引用即绑定到该临时对象。
用常量引用绑定不同类型
只要源值能隐式转换为目标类型,常量引用也可绑定:
int main()
{
const double& r1{ 5 }; // 临时 double 用 5 初始化,r1 绑定临时
std::cout << r1 << '\n'; // 5
char c{ 'a' };
const int& r2{ c }; // 临时 int 用 'a' 初始化,r2 绑定临时
std::cout << r2 << '\n'; // 97(int)
}
示例 1:临时 double
用 int
5 初始化;
示例 2:临时 int
用 char
‘a’ 初始化。
关键要点
若类型不匹配,编译器会生成同引用类型的临时对象并绑定;此时引用实际指向临时副本而非原对象,后续对原对象的修改不会反映到引用中。
示例(警示):
short bombs{ 1 };
const int& you{ bombs }; // 绑定的是临时 int(1)
--bombs; // bombs 变为 0
if (you) std::cout << "Boom!\n"; // 仍打印 Boom!
绑定到临时对象时的生命周期延长
临时对象通常在本表达式结束时销毁;但直接绑定到常量引用时,其生命周期延长至与引用一致,避免悬垂引用:
int main()
{
const int& ref{ 5 }; // 临时对象生命周期延长至 ref 作用域结束
std::cout << ref << '\n'; // 安全
} // ref 与临时对象同时销毁
关键要点
常量引用可绑定:可修改左值、不可修改左值、右值,灵活性远高于非常量左值引用。
(进阶提示)
生命周期延长仅适用于直接绑定;函数返回的 const 引用不触发此规则,详见 12.12 课。
constexpr 引用(可选)
在引用前加 constexpr
可使其在常量表达式中使用,但只能绑定到静态存储期对象(全局或 static
局部变量):
int g_x{ 5 };
int main()
{
constexpr int& ref1{ g_x }; // OK:全局
static int s_x{ 6 };
constexpr int& ref2{ s_x }; // OK:static 局部
int x{ 6 };
constexpr int& ref3{ x }; // 错误:非 static
}
若目标为 const
对象,需同时写 constexpr
与 const
:
static const int s_x{ 6 };
constexpr const int& ref{ s_x };
因限制较多,constexpr
引用实际使用较少。