int c =5; 代码解释
author: hjjdebug
date: 2025年 05月 27日 星期二 15:24:58 CST
descrip: int &&c =5; 代码解释
文章目录
- 1. c 的类型是右值引用.
- 2. c 的值类型是左值引用
- 3. 为什么会有这样的设计?
- 4. 总结:
- 5. 测试代码:
int &&c =5;
这么简单的代码, 竟不知有这么多内涵.
变量c 有两种身份, 类型和值类型.
1. c 的类型是右值引用.
因为c 被声明为 int &&, 所以类型是右值引用. 它只能bind到右值,这里bind到5
类型是右值的用途:
- 绑定临时对象,延长其生命周期(例如 5 是字面量,临时存在,但 c 将其生命周期延长到自己的作用域)
- 实现移动语义高效转移资源,(例如 std::vector 的数据所有权)
- 支持完美转发(std::forward)
2. c 的值类型是左值引用
所有具名变量(包括右值引用变量)在表达式中使用时,值类型均是左值。
左值的特征:
有名称(如 c 是变量名)
可以取地址(如 &c)
可以多次修改(如 c = 10)
3. 为什么会有这样的设计?
分离类型和值类别的意义?
右值引用的类型 (int&&) 是为了让编译器知道变量引用绑定到了右值.
而值类别(左值)是为了保证后续使用的安全性。
如果右值引用变量自动作为右值(连值类别也为右值),可能导致意外的资源转移:
例如:
str::string str=“I am a string”;
str::string &&s=str; // 此是s"值类型"是左值,类型是右值, 假如此时s 值类型自动变为右值.
use(s); //纯种右值,s的资源就可以被转移, 这样str的资源也就变成空了,谁要是用str就倒霉了,引起了混乱.
因此,具名的右值引用变量会被视为左值,避免隐式的资源转移,保证使用时的安全性
如果你确实想把值类别改为右值引用,可以用std::move()或static_cast()显式转换.
4. 总结:
类型是右值引用(int&&):表示 c 只能绑定到右值(如 5)
使用时是左值:因为 c 是具名变量,可以安全地多次访问和修改,避免隐式资源转移。
若要恢复右值属性: 需通过 std::move© 或 static_cast<int&&>© 显式转换。
完美转发转发的是"类型"而不是"值类型". 因为当前值类型都是据名左值引用.
而类型需要计算一下,是它父辈的类型传过来的.
说了半天,没有例子就是空谈.
给个例子吧.
5. 测试代码:
$ cat main.cpp
#include <stdio.h>
#include <utility>template <typename T>
void printType(T&& arg,const char *str) //万能引用
{printf("%-16s: ",str);//编译器是知道引用类型的if (std::is_lvalue_reference<decltype(arg)>::value){printf("Left value reference\n");}else if (std::is_rvalue_reference<decltype(arg)>::value){printf("Right value reference\n");}else{printf("I think this won't happen!\n");}
}int main()
{int &&c=5;printType(c,"c value type"); // c的值类型是左值引用, printType(std::forward<decltype(c)>(c),"c type"); //c的类型是右值引用
// printType(std::move<decltype(c)>(c)); //error: cannot bind rvalue reference of type ‘int&&’ to lvalue of type ‘int’
// int &a=5; //error: cannot bind non-const lvalue reference of type ‘int&’ to an rvalue of type ‘int’ int &a = c;printType(a,"a value type"); //a的"值类型"是左值引用printType(std::forward<decltype(a)>(a),"a type"); //a的"类型"是左值引用printType(std::move<decltype(a)>(a),"a move type"); //强制转化为右值引用return 0;
}
std::forward<decltype©, 可以获取到c的类型, 而c仅代表值类型, 这是本代码的核心之处.
而c的类型实际是从父辈那得到的.
为什么这样可以获取,背后的逻辑是什么,我就不多解释了,可看另一篇博客.
https://blog.csdn.net/hejinjing_tom_com/article/details/148253757?spm=1001.2014.3001.5501
执行结果:
$ ./tt
c value type : Left value reference
c type : Right value reference
a value type : Left value reference
a type : Left value reference
a move type : Right value reference