首页 > 编程语言 >c++左值、右值、右值引用

c++左值、右值、右值引用

时间:2022-10-30 13:11:57浏览次数:77  
标签:const 右值 int 左值 c++ 引用 test

c++左值、右值、右值引用

前言

这一部分对于规范代码、提高安全性、加速调试等方方面面都很重要、、问就是天天在引用和const上报红;出现诸如''表达式必须是 lvalue 或 xvalue"的错误;发现这些指针远不如我浅浅的理解中的那样简单,于是对其回炉重造!

先明确左值右值的概念

粗浅理解的话,等号左边的是左值、右边的是右值。但是它还不够明确:

int one = 1;
int another = one;

第一行中,我们令one为1,one作为左值存在;当程序执行到第二行,one此时算左值还是右值呢?

所以要关注左右值到底不同在哪,事实上可以理解为左值具有地址属性,也就是&x编译不报错则x是左值;左值关注的是地址,右值关注的是数据值。所以等号左边的只能是左值,右边的可以是左值也可以是右值。那么下面的i分别是左值还是右值?

int i = 0;
i++;
++i;

第一行,i作为有地址的量,做左值;第二行,i++是右值;第三行,++i是左值

i++是编译器先把i赋值给一个临时变量,完成当前的程序语句后,销毁临时变量并执行i+=1;而++i是先自增,立刻返回本身后执行当前的程序语句。

int x = 1, y = 123;
y = x++; // 先y=x=1,后x+=1;
y = ++x; // 先x+=1,后y=x;

字符串和int的区别

直接看图

image-20221030001707147

这里是因为编译器会单独为字符串开辟一个空间暂存,而数字不会。

静态语言中的变量

cpp是个静态语言,变量的定义就与动态语言不同:他的变量是有类型的。

也就是对于int a=1,在cpp里a的类型是int,a存放了数值1;而在js(动态语言)里a没有类型、js中的数值1是int类型的。

对于cpp:

  • 可以把int a当做一个盒子,里面放着1
  • 也可以把int a当做一个标签,对于1这个对象,我们为它贴了一个“是int类型、名字叫a”的标签

那么对于cpp中的变量,我们要是想拿到数值1,可以直接用a找到;而当我们想要拿到a、类型为int的a时,则需要用到左值引用(也就是我们常说的引用)。

关于左值引用

可以把它看做指针的语法糖,因为它做的就是把地址拿出来、把a单独拿出来。那么对于const int &x = 1,你认为其中的x是左值还是右值呢?如果声明y用这种方式:int &y = 1,则编译错误。因为我们提供的是y的引用、也就提供了一个地址,但是y现在刚被声明还莫得分配地址。

而对于const int &x,x也是在此时声明的,区别在所有的const都是常量。意味着虽然x还没开辟内存空间,但是它会被分配到常量中,编译器就能经过优化直接记录这个常量。

回到刚刚的问题,const int &x = 1,其中的x是左值。但是const就特殊在这里,它也可以引用右值;放到类的各种构造函数中它将发挥很大的作用

class test{
public:
    test(){};
    // 这里的两个const非常重要
    test(const test&){};	
    test& operator = (const test&){ return *this; }
};

// 将返回一个临时的test对象, 返回的test是右值, c17以后会做优化则能编译成功
test create_test(){
    return test();	
}

int main(){
    test x;
    test y(x);
    test z{create_test()};	// 复制构造函数
    z = create_test();      // 复制赋值
}

可以看到常量引用右值还是挺有用的,但是声明为const后,我们就无法修改它的值了(要么用不安全的强制类型转换)。为了让类可以实现上述操作,就出现了右值引用。

什么是右值引用

在上面我们执行test z{ create_test() }时,会把create_test()中返回的内容(接下来简称为X),X的结构和数值都拷贝给test z,也就是z根据X的样子新创建了一块大小一样的地址后,再把X中所有的数值拷贝一遍、贴到z的地址中。

由于拷贝了全部的内容,可能在性能上有所损耗(比如X是一个非常复杂的类)。于是出现了转移这种概念,我们可以把X的结构和数值转移给z。转移就相当于人的改名,相对克隆一个完全相同的小明,把他改名为小花会更简单。从另一个角度想,也是延长了小明本身的声明周期。这个过程中,也要用到右值引用。

int &&num = 1;	// 右值引用

使用类test:

test &&one_fromRight = create_test();

这样相当于延长X(create函数返回的那个右值对象)的生命了。如果你想看看更多关于类做对象的解释:https://www.cnblogs.com/bisa/p/16641056.html

std::move

声明移动,与右值引用配套使用

为什么说c++的指针危险?

因为指针可进行运算!因为指针可进行运算!因为指针可进行运算!它的运算意味着能指向任何一个未知的地址,如果操作不当,则造成数据混乱。

标签:const,右值,int,左值,c++,引用,test
From: https://www.cnblogs.com/bisa/p/16841052.html

相关文章

  • C++模板的偏特化与全特化
    全特化的目的:当为特殊类型时,需要特殊处理。偏特化的目的:固定几个类型,其他类型不确定。函数模板是不允许偏特化的,但函数允许重载,从而声明另一个函数模板即可替代偏特化的需......
  • 实验3 数组、指针与现代C++标准库
    task1代码:1#include<iostream>23usingstd::cout;4usingstd::endl;56//绫籄鐨勫畾涔?7classA{8public:9A(intx0,inty0):x{x0}......
  • c++,真有趣啊
    由于笔者的水平不太行,在这个贴里记录一些自己犯过的不太容易被发现的错误20221029基类classCBase{public:virtual~CBase(){}private:virtualbool__......
  • C++11 unistring 类(编码转换)
    C++11 的编码转换程序: #ifndefUNISTRING_HPP#defineUNISTRING_HPP#include<algorithm>#include<codecvt>#include<cstdio>#include<cstdarg>#include<i......
  • C++ Primer Plus学习笔记之复合类型(上)
    前言个人觉得学习编程最有效的方法是阅读专业的书籍,通过阅读专业书籍可以构建更加系统化的知识体系。一直以来都很想深入学习一下C++,将其作为自己的主力开发语言。现在为......
  • C++求高精度pi(1)BBP公式
    C++求高精度pi(1)前言(之后再写)BBP公式由arctan1展开得到的莱布尼茨级数是一个交错级数,并且条件收敛而不绝对收敛,这注定了莱布尼兹级数方法会非常低效而BBP公式$$\sum......
  • C++ STL
    概述STL主要有container,algorithm和iterator三大部分构成容器用于存放数据对象算法用于操作容器中的数据对象迭代器是算法和容器之间的中介STL容器STL容器是一种数据结构......
  • Modf is not a member of std in C++
    ModfisnotamemberofstdinC++ 2minuteread OnthispageIntroductionPotentialcausesFix#1:AddiostreamtoyourdepedenciesFix#2:Usingnamesp......
  • python 与C++ 利用socket实现json数据传输
    单机python与C++程序利用socket实现json数据传输目录单机python与C++程序利用socket实现json数据传输需求实现方法的选择具体实现流程图示涉及到的技术1socket......
  • C++ 实现argosort
    #include<bits/stdc++.h>usingnamespacestd;intmain(){intn=5,t;vector<int>a,b;for(inti=0;i<n;++i){scanf("%d",&t......