C++引用、左值和右值

举报
用户已注销 发表于 2021/11/19 00:42:02 2021/11/19
1.8k+ 0 0
【摘要】 目录 一,引用 1,函数参数引用传递 2,引用型变量 3,函数返回引用型 二,左值和右值 1,左值和右值 2,表达式 3,取址和解地址 4,引用和const 5,move 6,右值引用 一,引用 1,函数参数引用传递 #include<iostream>using namespace std; ...

目录

一,引用

1,函数参数引用传递

2,引用型变量

3,函数返回引用型

二,左值和右值

1,左值和右值

2,表达式

3,取址和解地址

4,引用和const

5,move

6,右值引用


一,引用

1,函数参数引用传递


      #include<iostream>
      using namespace std;
      void f(int& x)
      {
          x--;
      }
      int main()
      {
         int x=3;
         f(x);
          cout<<x;
         return 0;
      }
  
 

输出2

常见错误:


      void f(int& x)
      {
          x--;
      }
      int main()
      {
         f(3);
         return 0;
      }
  
 

2,引用型变量


      #include<iostream>
      using namespace std;
      int main()
      {
         int x=3;
         int& x2=x;
          x2++;
          cout<<x;
         return 0;
      }
  
 

输出4

常见错误:


      int main()
      {
         int& x = 3;
         return 0;
      }
  
 

3,函数返回引用型


      #include<iostream>
      using namespace std;
      int& f(int arr[],int id)
      {
         if(id>sizeof(arr)/sizeof(int))id=0;
         return arr[id];
      }
      int main()
      {
         int arr[]={1,2,3};
         f(arr,1)++;
         f(arr,10)++;
          cout<<arr[0]<<arr[1]<<arr[2];
         return 0;
      }
  
 

输出233

二,左值和右值

1,左值和右值

左值就是有内存地址的,可以用&取地址,右值是没有内存地址的,也就不能取址。

首先,等号左边必须是左值,右边可以是左值可以是右值


         int x = 1; // 正确,x是左值,1是右值
         1 = x; // 错误
         int a = x; // 正确, a是左值
          a + 1 = 0; // 错误,a+1是右值
  
 

PS:除非对运算符做了重载,否则我们指的都是默认运算符,下同。

其次,字面值是右值,匿名变量是右值

最后,左值和右值描述的其实是变量是否作为一个对象保存在计算机中,和存储的位置是不是在内存中没有绝对的关系

比如左值变量用register修饰,虽然保存在寄存器中,但仍然是左值。而如果对register变量取址,那么它一开始就不会被放入寄存器。

2,表达式

有的表达式产生的是左值,有的表达式产生的是右值。


      int main()
      {
         int x = 1, y = 2;
          x + 1; // 右值
          x + y; // 右值
          x++; // 右值
          &x; // 右值
         int* a; // 左值
          *a; // 左值
          a + 1; // 右值
          *(a + 1); // 左值
         return 0;
      }
  
 

一般匿名变量指的就是表达式产生的右值,但也不绝对,例如*(a + 1)这个匿名变量就是左值。

3,取址和解地址

取址 & 是根据左值得到右值,解地址 * 是根据左值或者右值得到左值。

即取址 & 只能用于左值,而 * 都可以。

4,引用和const

& 作为引用时,是可以用于右值的。


      void f(const int &x)
      {
          cout << x;
      }
      int main()
      {
         f(3);
         return 0;
      }
  
 

即,非const的左值引用、const的左值和右值引用都是可以的,非const的右值引用是不行的

而这居然是可以的:


      void f(const int &constant)
      {
          cout << constant;
         const int* const_p = &constant;
         int* modifier = const_cast<int*>(const_p);
          (*modifier)++;
          cout << constant;
      }
      int main()
      {
         f(3);
         return 0;
      }
  
 

输出34

而如果是这样:


      void f(const int &constant)
      {
         const int* const_p = &constant;
         int* modifier = const_cast<int*>(const_p);
          (*modifier)++;
      }
      int main()
      {
         const int x = 3;
         f(x);
          cout << x;
         return 0;
      }
  
 

输出3

说明参数相当于是按值传递的。

换个角度看,f(3)其实是右值引用,f(x)是左值引用。

5,move

move函数可以实现把左值换成右值


      template <class _Ty>
      _NODISCARD constexpr remove_reference_t<_Ty>&& move(_Ty&& _Arg) noexcept { // forward _Arg as movable
         return static_cast<remove_reference_t<_Ty>&&>(_Arg);
      }
  
 

其实也就是把一个变量本身作为返回值,函数的返回值自然就是右值。

6,右值引用

用&&做单目运算符时,表示右值引用。

Compiler Explorer可以在线编译代码。

下面2个代码的汇编是一样的:


      void f(int &&constant)
      {
         return;
      }
      int main()
      {
         f(3);
         return 0;
      }
  
 


      void f(const int &constant)
      {
         return;
      }
      int main()
      {
         f(3);
         return 0;
      }
  
 

对于右值,其实只是没有给它取名字而已,和左值变量的主要区别在于内存,而在寄存器处,对于计算来说是一样的。

而右值引用这个新语法,使得我们可以像左值引用一样,直接引用一个变量而不用copy,从而高效引用右值,这就是移动语义、完美转发。

从网上盗了一张图:

这里写图片描述

文章来源: blog.csdn.net,作者:csuzhucong,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/nameofcsdn/article/details/117453152

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

作者其他文章

评论(0

抱歉,系统识别当前为高风险访问,暂不支持该操作

    全部回复

    上滑加载中

    设置昵称

    在此一键设置昵称,即可参与社区互动!

    *长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

    *长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。