C++右值引用、移动语义和完美转发

本文详细介绍了C++中的左值引用和右值引用,包括它们的概念、用途和区别。左值引用不能绑定到右值,而右值引用则用于优化资源转移,如移动语义。通过示例展示了右值引用如何用于函数参数传递和返回,以及移动构造函数在减少拷贝开销中的作用。此外,还提到了完美转发的概念,它允许函数参数在传递过程中保持其原始右值属性。
摘要由CSDN通过智能技术生成

右值引用

左值(lvalue, left value),顾名思义就是赋值符号左边的值。准确来说, 左值是表达式(不一定是赋值表达式)后依然存在的持久对象。

右值(rvalue, right value),右边的值,是指表达式结束后就不再存在的临时对象。
纯右值(prvalue, pure rvalue),纯粹的右值,要么是纯粹的字面量,例如 10, true; 要么是求值结果相当于字面量或匿名临时对象,例如 1+2。非引用返回的临时变量、运算表达式产生的临时变量、 原始字面量、Lambda 表达式都属于纯右值。
将亡值(xvalue, expiring value),是 C++11 为了引入右值引用而提出的概念(因此在传统 C++ 中, 纯右值和右值是同一个概念),也就是即将被销毁、却能够被移动的值。

概述:引用的本质是别名,可以通过别名修改变量的值,转参时传引用避免拷贝。

  • 左值引用:指向左值,不能指向右值的引用。const左值引用可以指向右值。
int main() {
  int a = 5;          // a是个左值
  int &ref_a_left = a;// 左值引用指向左值
  const int &ref_left = 5; // const左值引用可以指向右值
  cout << ref_a_left << endl; // 5
  cout << a; // 5
}
  • 右值引用:指向右值,不能指向左值。
int main() {
  int &&lref = 5;
  // int &&lref2 = lref; 
  // lref拥有名称,是有地址的,是左值。
}
  • 被声明出来的左、右值应用都是左值。

  • 函数参数:

#include <iostream>

using namespace std;

int change(int &&a) {
  a = 10;
  return a;
}

int change2(int &a) {
  a = 10;
  return a;
}

int change3(int a) {
  a = 10;
  return a;
}

int main() {
  int &&rref = 5;
  int ref = 5;
  int &lref = ref;

  // 测试右值引用
  // cout<<change(rref)<<endl; 编译不通过,右值引用是左值
  cout << change2(rref) << endl;
  cout << change3(rref) << endl;

  // cout << change(lref) << endl; 编译不通过,左值不能作为右值函数参数
  cout << change2(lref) << endl;
  cout << change3(lref) << endl;

  // cout << change(ref) << endl; 编译不通过,左值不能作为右值函数参数
  cout << change2(ref) << endl;
  cout << change3(ref) << endl;
}

移动语义

概述:各种情况下对象的资源所有权转移问题。

解决的场景:

  1. 按值传入参数
  • 如果使用const string& name作为参数,就会调用一次构造函数和移动构造函数
class person {
public:
  person (string name) 
  : name_(move(name))
  {
  }
  string name_;
};

person p("Alice");

string bn = "Bob";
person p1(bn); 
  • 显式移动构造,将传入的字符串移入成员变量。
  1. 按值返回
vector<int> test() {
  vector<int> v;
  return v;
}

编译成:

std::vector<int, std::allocator<int> > test()
{
  vector<int> v = std::vector<int, std::allocator<int> >() /* NRVO variable */;
  return std::vector<int, std::allocator<int> >(static_cast<std::vector<int, std::allocator<int> > &&>(v));
}
  1. 接收右值表达式
    优化表达式的值初始化对象或者给对象复制的性能。现在函数直接利用这些右值。

完美转发

std::forward成为完美转发,即经过转发的值的属性不变。没有完美转发的情况下,经过函数传参使得右值转为左值。

#include <iostream>
using namespace std;

void print(int &a) {
  cout << "左值" << endl;
}

void print(int &&a) {
  cout << "右值" << endl;
}

template<typename X>
void test(X &&x) {
  print(x);
  print(std::forward<X>(x));
  print(std::move(x));
}

int main(int argc, char *argv[]) {
  int a = 10;
  test(a);
  cout << "============" << endl;
  test(10);
}
/** 
左值
左值
右值
============
左值
右值
右值
**/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值