c++左值和右值的区别

本文讲述了C++中左值和右值的概念,包括它们在表达式中的角色、身份特征、可修改性以及在函数重载中的应用。左值具有持久地址,可多次使用,而右值是非持久的临时对象,仅在赋值表达式中可见。

在c++ 中左值和右值是表达式的两种类别, 他们的主要区别在于对象的身份可移动性

1. 左值(Lvalue)

左值是指那些表达式结束之后依然存在的对象,他们有明确的持久地址(内存地址) ,通俗来说,左值可以看作一个篮子,即便你往篮子里面放入或者取处之后,篮子(变量)依然存在,你可以多次使用它 。

  • 你可以对左值取地址
  • 左值可以出现在赋值表达式的左边或者右边
  • 函数返回一个非引用类型时,通常返回的是右值,但是如果函数返回一个引用类型是,那么返回的是左值
    比如说, int x = 10 ; x就是一个左值

2. 右值(Lvalue)

右值指的是不具有持久地址的临时对象 , 当表达式结束后他们就不存在了,右值更像手中的苹果,用完之后 , 它就不存在了, 这种临时性质使得它们可以被“移动” , 而不仅仅是被“拷贝”

  • 不能对右值进行取地址
  • 右值只能出现在赋值表达式的右边
  • 字面值 (如 10 , a)返回返回临时对象或表达式生成的临时结果都是右值
    比如 表达式10 , x+ 2 std::string(“hello”) 中的10 x+2 以及通过构造函数生成的字符串都是右值

3.右值和左值的区别

  • 身份: 左值有持久的内存地址, 而右值常常都是临时的
  • 可修改性: 左值可以被重新赋值, 而右值不可以
  • 函数重载:在函数重载中,可以根据参数是左值还是右值选择不同的函数进行实现
### 的基本概念 在 C++ 中,(lvalue)(rvalue)是表达式(expression)的分类,它们的核心区别在于是否具有持久的身份(identity)可寻址性。通常表示一个具有名称、可被取地址的对象,而表示一个临时的、通常无法取地址的。 - 可以出现在赋表达式的侧或侧,例如变量、数组元素、解引用的指针等。 - 通常是临时,例如字面量、函数返回的临时对象、表达式的结果等,它们通常无法被直接修改或取地址。 ### 引用与引用 C++ 中引入了两种引用类型来绑定: 1. **引用**:使用 `&` 声明,绑定到引用常用于避免不必要的拷贝操作,例如传递大对象时使用引用传递。 ```cpp int x = 10; int& ref = x; // ref 是引用,绑定到 x ``` 2. **引用**:使用 `&&` 声明,绑定到引用是 C++11 引入的特性,主要用于实现移动语义完美转发。 ```cpp int x = 10; int&& ref = 42; // ref 是引用,绑定到 42 int&& ref2 = std::move(x); // std::move(x) 将 x 转换为 ``` ### 区别 1. **生命周期与持久性**: - 通常具有较长的生命周期,它们是命名的对象,可以通过名称访问修改。 - 通常是临时对象,生命周期较短,通常在表达式结束后立即销毁。 2. **绑定规则**: - 非常量引用只能绑定到非常量,不能绑定到常量。 ```cpp int val1 = 10; const int val2 = 10; int val3 = 10; int& lrval1 = val1; // 正确:非常量引用非常量 int& lrval2 = val2; // 错误:非常量引用常量 int& lrval3 = val1 + val3; // 错误:非常量引用非常量 int& lrval4 = 10; // 错误:非常量引用常量(字面量常量) ``` - 引用可以绑定到,但不能绑定到,除非使用 `std::move` 显式转换。 3. **移动语义**: - 引用的引入使得移动语义成为可能。移动语义允许将资源从临时对象()转移到新对象,避免不必要的拷贝操作。 - 例如,`std::vector` 的移动构造函数可以将临时对象的内部缓冲区直接转移给新对象,而不是进行深拷贝。 4. **函数参数传递**: - 在函数参数传递中,引用引用的使用会影响参数的处理方式。引用参数在函数内部被视为,因此需要再次使用 `std::forward` 或 `std::move` 来保持其性质。 ### 示例代码 以下是一些示例代码,展示了的用法: #### 引用示例 ```cpp int main() { int x = 10; int& ref = x; // 引用绑定到 x ref = 20; // 修改 x 的 return 0; } ``` #### 引用示例 ```cpp #include <iostream> #include <utility> int main() { int x = 10; int&& ref = 42; // 引用绑定到 42 int&& ref2 = std::move(x); // 将 x 转换为 std::cout << "ref: " << ref << ", ref2: " << ref2 << std::endl; return 0; } ``` #### 移动语义示例 ```cpp #include <iostream> #include <vector> class MyClass { public: std::vector<int> data; MyClass(int size) : data(size, 0) {} MyClass(MyClass&& other) noexcept : data(std::move(other.data)) {} // 移动构造函数 }; int main() { MyClass obj1(1000000); MyClass obj2 = std::move(obj1); // 使用移动构造函数 return 0; } ``` ### 总结 区别在于它们的表达式类型、生命周期以及绑定规则。引用引用的引入使得 C++ 在资源管理性能优化方面更加灵活。通过移动语义,引用可以有效地避免不必要的拷贝操作,提高程序的效率。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值