被const引用延长生命周期的右值存储位置及未定义行为问询
聊聊C++中右值存储、const引用绑定及const_cast的那些疑问
先把你贴的代码放出来方便讨论:
#include <iostream> #include <cstdlib> int main() { int a = 7; // 7这个右值存储在程序二进制文件中,被赋值给"a" int b = 7 * rand(); // 7从程序二进制文件中取出,与rand()的结果相乘后赋值给"b" // 但是…… const int& c = 3; // 3是右值吗? const_cast<int&>(c) = 1; // 右值没有存储空间?但我正在给它赋值。 std::cout << c; // 输出1 }
咱们逐个解决你的疑问:
1. 绑定到const引用的右值:存储空间与值类别
首先明确两个核心规则:
- 普通的右值临时对象(比如
7*rand()的计算结果)确实没有持久存储空间,生命周期到所在语句结束就终止,用完就被销毁。 - 但当你把右值绑定到const左值引用(比如
const int& c = 3;)时,C++标准强制要求编译器为这个右值创建一个临时对象,并把引用绑定到这个临时对象上。这个临时对象会被分配栈内存,而且它的生命周期会被延长到和引用c完全一致——也就是直到main函数结束。
那这个临时对象还是右值吗?
- 临时对象本身的值类别是右值,但通过引用
c访问它时,引用本身是左值。你可以把这个过程理解成编译器偷偷帮你做了:
所以int temp = 3; // 创建临时非const对象 const int& c = temp; // 用const引用绑定它3这个字面量本身是右值,但绑定后生成的临时对象是有存储的,只是它的源头是右值而已。
2. const_cast赋值是否属于未定义行为?
这得分场景看,但你的代码里这种情况是合法的:
- 你绑定的临时对象本身不是const类型——它是普通的
int对象,const只是引用的属性,不是对象自身的属性。 - 用
const_cast<int&>(c)去掉引用的const限定后,你得到的是指向这个非const临时对象的左值引用,对它赋值完全合法,不属于未定义行为。这就是为什么你的代码能输出1——临时对象确实被成功修改了。
但要敲个警钟:如果你的引用绑定的是本身就是const的对象(比如const int x = 3; const int& c = x;),那用const_cast去掉const后修改它就是未定义行为。因为这类const对象可能被编译器放在只读内存里,修改会导致崩溃或不可预测的结果。
额外补充:字面量的存储细节
你提到的7这种整数字面量,编译时会被放在程序二进制的只读数据段(比如.rodata)里。执行int a =7;时,程序会把只读段里的值复制到栈上的变量a中。而像7*rand()这种运行时计算的右值,结果会暂存在寄存器或临时栈空间里,语句结束就释放——除非被const引用绑定延长生命周期。
内容的提问来源于stack exchange,提问作者Zebrafish
相关产品推荐
相关产品推荐

