[C++] C++11新特性之左值右值、左值引用右值引用、mov、forward

2021/8/6 14:36:01

本文主要是介绍[C++] C++11新特性之左值右值、左值引用右值引用、mov、forward,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

参考

  • C++ Primer
  • C++ 11 左值,右值,左值引用,右值引用,std::move, std::foward

左值右值

C++的表达式要么是左值,要么是右值。

简单说,左值可以位于赋值语句的左边,右值则不能。

  • 右值:当一个对象被用作右值的时候,用的是对象的值(内容),右值要么是字面常量,要么在表达式求值过程中创建的临时对象,没有名字,不能被赋值。
  • 左值:当一个对象被用作左值的时候,用的是对象的身份(在内存中的位置),左值就是有名字的对象,可以被赋值,左值可以被取地址,左值持久
  • 需要右值的地方可以用左值来代替,不能把右值当成左值使用,当左值当成右值使用的时候,实际上使用的是它的内容(值)

需要用到左值

  • 赋值运算符需要一个(非常量)左值作为其左侧运算对象,得到的结果仍然是一个左值
  • 取地址符作用于一个左值运算对象,返回指向该运算对象的指针,这个指针是一个右值
  • 内置解引用运算符、下标运算符、迭代器解引用运算符、string和vector的下标运算符求值结果都是左值
  • 内置类型和迭代器的递增递减运算符作用于左值运算对象,前置版本作用的和得到的都是左值

左值引用右值引用

#include <iostream>

//函数重载,形参为左值引用,接受左值
void process_value(int& i) { 
  std::cout << "LValue processed: " << i << std::endl; 
} 

//函数重载,形参为右值引用,接受右值
void process_value(int&& i) { 
  std::cout << "RValue processed: " << i << std::endl; 
} 

int main() { 
  int a = 0; 
  process_value(a);//传入左值,输出:LValue processed: 0
  process_value(1);//传入右值,输出1:RValue processed: 1
}
  • 左值引用&:不能将一个左值引用绑定到要求转换的表达式、字面常量或者返回右值的表达式

  • 右值引用&&:某个对象的另一个名字,可以将一个右值引用绑定到要求转换的表达式、字面常量或者返回右值的表达式,不能将右值引用直接绑定到一个左值上,右值引用指向将要被销毁的对象,用右值引用接管所引用的对象的资源

    int i = 1;
    int &&p = i;//错误,不能将一个右值引用绑定到一个左值上
    int &q = i * 22;//错误,不能将左值引用绑定到返回右值的表达式,i * 22是一个右值
    int &&q2 = i * 22;//正确,右值引用可以绑定到乘法右值结果上
    
  • 可以把左值引用绑定到返回左值的表达式(返回左值引用的函数、赋值、下标、解引用、前置递增递减运算符

    int i = 1;
    int &r = i;//正确,左值引用
    
  • 可以把const左值引用或者右值引用绑定到返回右值的表达式(返回非引用类型的函数、算术、关系、位、后置递增递减运算符

    const int &q1 = i * 22;//正确,可以将const引用绑定到右值
    
  • p是右值引用,指向一个右值,p本身是左值

    include <iostream>
    
    //函数重载,形参为左值引用,接受左值
    void process_value(int& i) { 
      std::cout << "LValue processed: " << i << std::endl; 
    } 
    
    //函数重载,形参为右值引用,接受右值
    void process_value(int&& i) { 
      std::cout << "RValue processed: "  << std::endl; 
    } 
    
    int main() { 
      int a = 0; 
      process_value(a);//输出:LValue processed: 0,说明传入的是左值
      int&& p = 3;
      process_value(p); //输出:LValue processed: 3,说明传入的是左值
    }
    //以上例子说明p是右值引用,指向一个右值,p本身是左值
    

    不能将一个右值引用绑定到一个右值引用类型的变量上

    变量是左值,不能将一个右值引用直接绑定到一个变量上

    int &&p = 11;//正确,字面常量是右值
    int &&q = p;//错误,p是左值
    
  • 右值引用的意义

    • 为临时变量续命,也就是为右值续命,因为右值在表达式结束后就消亡了,如果想继续使用右值,那就会动用昂贵的拷贝构造函数。

    • 右值引用是用来支持转移语义的。转移语义可以将资源 ( 堆,系统对象等 ) 从一个对象转移到另一个对象,这样能够减少不必要的临时对象的创建、拷贝以及销毁,能够大幅度提高 C++ 的性能。

    • 转移语义是和拷贝语义相对的,可以类比文件的剪切与拷贝,当我们将文件从一个目录拷贝到另一个目录时,速度比剪切慢很多。

C++11 之move函数

头文件utility

使用move函数将获得一个绑定到左值上的右值引用类型

int &&p = 11;//正确,字面常量是右值
int &&q = p;//错误,p是左值
int &&q = std::move(p);//正确,move返回给定对象的右值引用

对于move不提供using声明,必须写成std::move,不能写成move

C++11 之forward

头文件utility

与move不同,forward必须通过显式模板实参来调用

forward返回该显式实参类型的右值引用,即forward返回的是T&&

template <typename F, typename T1, typename T2>
void flip(F f, T1 &&t1, T2 &&t2) {
    f(std::forward<T2>(t2), std::forward<T1>(t1));
}

//如果调用flip(g, i, 42),i将以int&类型传递给g,42将以int&&类型传递给g


这篇关于[C++] C++11新特性之左值右值、左值引用右值引用、mov、forward的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程