左值和右值

news2024/11/27 4:37:08

左值和右值

按字面意思,通俗地说。以赋值符号 = 为界,= 左边的就是左值,= 右边就是右值。

更深一层,可以将 L-valueL, 理解成 Location,表示定位,地址。将 R-valueR 理解成 Read,表示读取数据。

左值右值判断技巧: 如果在表达式的下一行可以用单一变量表示输出结果,则为左值。否则该表达式的值存储在临时匿名内存中,则为右值。 左值持久,右值短暂

  • T & 代表左值引用,可以绑定到左值上。

  • T && 代表右值引用,可以绑定到右值上。

有BUG版:

void judge2(int &val) {
    cout << "[judge2 left  value] ";
    return ;
}

void judge2(int &&val) {
    cout << "[judge2 right value] ";
    return ;
}

void judge1(int &val) {
    cout << "[judge1 left  value] ";
    judge2(val);     //val此时是个常态,所以一定是左值
    return ;
}

void judge1(int &&val) {
    cout << "[judge1 right value] ";
    judge2(val);     //val此时是个常态,所以一定是左值
    return ;
}

#define TEST(x) { \
    judge1(x); \
    printf(" %7s  %d\n", #x, x); \
}

int main() {
    int x = 1, y = 2;
    printf("x = %d, y = %d\n", x, y);
    TEST(x);
    TEST(x + y);
    TEST(x + 1);
    TEST(x += 1);
    TEST(++x);
    TEST(x++);
    return 0;
}
x = 1, y = 2
[judge1 left  value] [judge2 left  value]        x  1
[judge1 right value] [judge2 left  value]    x + y  3
[judge1 right value] [judge2 left  value]    x + 1  2
[judge1 left  value] [judge2 left  value]   x += 1  3
[judge1 left  value] [judge2 left  value]      ++x  5
[judge1 right value] [judge2 left  value]      x++  6

无BUG版:

move()forward<type>()主要解决引用函数参数为右值时,传进来之后有了对象就变成了左值。

void judge2(int &val) {
    cout << "[judge2 left  value] ";
    return ;
}

void judge2(int &&val) {
    cout << "[judge2 right value] ";
    return ;
}

void judge1(int &val) {
    cout << "[judge1 left  value] ";
    //judge2(val);
    judge2(forward<int &>(val));
    return ;
}

void judge1(int &&val) {
    cout << "[judge1 right value] ";
    //judge2(move(val));   //move可以强制转换成右值
    judge2(forward<int &&>(val));   //forward一种通用方式
    return ;
}

#define TEST(x) { \
    judge1(x); \
    printf(" %7s  %d\n", #x, x); \
}

int main() {
    int x = 1, y = 2;
    printf("x = %d, y = %d\n", x, y);
    TEST(x);
    TEST(x + y);
    TEST(x + 1);
    TEST(x += 1);
    TEST(++x);
    TEST(x++);
    return 0;
}
x = 1, y = 2
[judge1 left  value] [judge2 left  value]        x  1
[judge1 right value] [judge2 right value]    x + y  3
[judge1 right value] [judge2 right value]    x + 1  2
[judge1 left  value] [judge2 left  value]   x += 1  3
[judge1 left  value] [judge2 left  value]      ++x  5
[judge1 right value] [judge2 right value]      x++  6

  

const类型的引用

  • 如果引入const类型的引用,那么一个值可以与多个重载的函数参数绑定时,要注意优先级。

在这里插入图片描述

class A {};

void func(A &obj) {
    cout << "left value" << endl;
    return ;
}

void func(const A &obj) {
    cout << "const left value" << endl;
    return ;
}

int main() {
    A a;
    func(a);   // 优先找左值引用做参数的函数。没有找到退而求其次找const左值引用做参数的函数。
    return 0;
}
class A {};

void func(const A &obj) {
    cout << "const left value" << endl;
    return ;
}

void func(A &&obj) {
    cout << "right value" << endl;
    return ;
}


void func(const A &&obj) {
    cout << "const right value" << endl;
    return ;
}

int main() {
    func(A());
    return 0;
}
class A {};

void func(const A &obj) {
    cout << "const left value" << endl;
    return ;
}

void func(A &&obj) {
    cout << "right value" << endl;
    return ;
}

void func(const A &&obj) {
    cout << "const right value" << endl;
    return ;
}

int main() {
    const A a;
    func(move(a));  // 优先绑定const右值引用,没有找const左值引用。即使有右值引用也绑定不上,因为实参为const类型
    return 0;
}

  

  • 注意:函数的形式参数为const类型引用可以触发重载,但是const类型的值不可以触发重载。

    个人理解这种传值情况,无论形参是否为const都不会影响形参的值,所以无意义。而传地址(引用)时,const限定则有实意。

// 不能触发重载
void func(const int a) {
    return ;
}

void func(int a) {
    return ;
}

  

  

  

移动构造函数

  所谓移动语义,指的就是以移动而非深拷贝的方式初始化含有指针成员的类对象。简单的理解,移动语义指的就是将其他对象(通常是临时对象)拥有的内存资源 “移为已用”

  事实上,对于程序执行过程中产生的临时对象,往往只用于传递数据(没有其它的用处),并且会很快会被销毁。因此在使用临时对象初始化新对象时,我们可以将其包含的指针成员指向的内存资源直接移给新对象所有,无需再新拷贝一份,这大大提高了初始化的执行效率。

故事分析:

  • 对于深拷贝来说犹如一个师傅从小培养一个徒弟,在几十年的时间里,师傅一点一点教,徒弟一点一点学,最后徒弟学会了师傅所有东西,变得和师傅一样强。

  • 对于移动构造来说,师傅在濒危时候才收一个徒弟,这时候师傅用传功的方式瞬间把必胜绝学都传给了徒弟,而师傅散功而死。

  我们知道,非 const 右值引用只能操作右值,程序执行结果中产生的临时对象(例如函数返回值、lambda 表达式等)既无名称也无法获取其存储地址,所以属于右值。当类中同时包含拷贝构造函数和移动构造函数时,如果使用临时对象初始化当前类的对象,编译器会优先调用移动构造函数来完成此操作。只有当类中没有合适的移动构造函数时,编译器才会退而求其次,调用拷贝构造函数。

  在实际开发中,通常在类中自定义移动构造函数的同时,会再为其自定义一个适当的拷贝构造函数,由此当用户利用右值初始化类对象时,会调用移动构造函数;使用左值(非右值)初始化类对象时,会调用拷贝构造函数。

  

Q:如果使用左值初始化同类对象,但也想调用移动构造函数完成,有没有办法可以实现呢?

A:默认情况下,左值初始化同类对象只能通过拷贝构造函数完成,如果想调用移动构造函数,则必须使用右值进行初始化。C++11 标准中为了满足用户使用左值初始化同类对象时也通过移动构造函数完成的需求,新引入了 std::move() 函数,它可以将左值强制转换成对应的右值,由此便可以使用移动构造函数。

class A {
public:
    A() : data(new int[5]), __size(5) {
        //1, 2, 3, 4, 5
        for (int i = 1; i <= __size; ++i)  data[i - 1] = i;
        cout << this << "  default constructor" << endl;
    }
    A(const A &obj) : data(new int[5]), __size(5) {
        for (int i = 0; i < __size; ++i)  data[i] = obj.data[i];
        cout << this << "  deep_copy constructor" << endl;
    }
    A(A &&obj) : __size(5) {    //Cannot be const, because const object is read-only
        data = obj.data;
        obj.data = nullptr;
        obj.__size = 0;
        cout << this << "  move constructor" << endl;
    }

    A& operator++() {
        for (int i = 0; i < __size; ++i)  ++data[i];
        return *this;
    }
    A operator++(int) {
        A obj(*this);
        for (int i = 0; i < __size; ++i)  ++data[i];
        return obj;
    }
    void show() {
        if (data == nullptr) {
            cout << "NULL" << endl;
            return ;
        }
        for (int i = 0; i < __size; ++i) {
            cout << data[i] << " ";
        }
        cout << endl;
        return ;
    }

    virtual ~A() {
        delete data;
        cout << this << "  deconstructor" << endl;
    }
private:
    int *data, __size;
};

int main() {
    cout << "A a ----------------------------------BEGIN" << endl;
    A a;
    cout << "a : ";  a.show();
    cout << "A b(++a) -----------------------------BEGIN" << endl;
    A b(++a);
    cout << "a : ";  a.show();
    cout << "b : ";  b.show();
    cout << "A c(a++) -----------------------------BEGIN" << endl;
    A c(a++);
    cout << "a : ";  a.show();
    cout << "c : ";  c.show();
    cout << "A d(move(a)) -----------------------------BEGIN" << endl;
    A d(move(a));
    cout << "a : ";  a.show();
    cout << "d : ";  d.show();
    return 0;
}

现在的编辑器会自动优化(RVO)。假如想体现出效果,记得编译时加参数 -fno-elide-constructors

其作用为 return x 时 (x为对象)减小开销,直接把该片内存的管理权(this指针)给目标对象。

A a ----------------------------------BEGIN
0x7fffdbe89260  default constructor
a : 1 2 3 4 5
A b(++a) -----------------------------BEGIN
0x7fffdbe89280  deep_copy constructor
a : 2 3 4 5 6
b : 2 3 4 5 6
A c(a++) -----------------------------BEGIN
0x7fffdbe89220  deep_copy constructor
0x7fffdbe892c0  move constructor
0x7fffdbe89220  deconstructor
0x7fffdbe892a0  move constructor
0x7fffdbe892c0  deconstructor
a : 3 4 5 6 7
c : 2 3 4 5 6
A d(move(a)) -----------------------------BEGIN
0x7fffdbe892c0  move constructor
a : NULL
d : 3 4 5 6 7
0x7fffdbe892c0  deconstructor
0x7fffdbe892a0  deconstructor
0x7fffdbe89280  deconstructor
0x7fffdbe89260  deconstructor

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/85999.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[附源码]Python计算机毕业设计电影售票管理系统Django(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程 项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等…

什么是位移电流?位移电流密度计算公式详解

位移电流变化着的电场可以存在于真空、导体、电介质中&#xff0c;本质是变化着的电场&#xff0c;不会产生化学效应&#xff0c;也不会产生焦耳热。下面一起随着小编一起了解一下什么是位移电流以及位移电流密度计算公式。 什么是位移电流&#xff1f; 1861年&#xff0c;詹姆…

[附源码]Python计算机毕业设计SSM基于web的医院门诊管理系统(程序+LW)

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

基于java+springboot+mybatis+vue+mysql的一起来约苗系统

项目介绍 在系统流程分析当中调查分析它是比较重要的环节&#xff0c;因为在这个系统当中它都涉及到每个环节的业务流程&#xff0c;所以从JavaSprignBootVueMYSQL一起来约苗系统的设计的整体设计上要保证各个信息的正确输入和输出以及对数据储存的完整&#xff0c;并结合实际…

ASEMI肖特基二极管MBR20100FCT图片,MBR20100FCT大小

编辑-Z ASEMI肖特基二极管MBR20100FCT参数&#xff1a; 型号&#xff1a;MBR20100FCT 最大重复峰值反向电压&#xff08;VRRM&#xff09;&#xff1a;100V 最大RMS电桥输入电压&#xff08;VRMS&#xff09;&#xff1a;70V 最大直流阻断电压&#xff08;VDC&#xff09;…

python+django车辆充电桩管理系统

启动一个新项目 执行下面的命令来创建一个新的 Django 项目&#xff1a; django-admin startproject myproject 命令行工具django-admin会在安装Django的时候一起自动安装好。 执行了上面的命令以后&#xff0c;系统会为Django项目生成基础文件夹结构。 现在&#xff0c;我…

【软件测试】测试人我懵了,产品验收时还有一堆bug?

目录&#xff1a;导读前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09;前言 为什么明明写了 100…

屏幕录制怎么加上水印?这个方法,真的太实用啦

随着网络技术的飞速发展&#xff0c;短视频已经成为传播信息最快的方式之一。越来越多的人将自己喜欢的游戏直播视频和网络直播课程知识制作成短视频&#xff0c;并在各大媒体平台进行分享。然后&#xff0c;录制的视频可能会被其他人带到其他平台。屏幕录制怎么加上水印&#…

FLStudio21水果软件中文版本有哪些新增功能?

FL Studio 21即将推出 – 新功能和改进。如果您从事音乐制作&#xff0c;那么您不可能没有听说过 FL Studio&#xff0c;或者很可能已经使用过这个音乐程序。好了&#xff0c;新版本的 FL Studio 21 DAW 已经准备好向公众发布了。Image-line 正在为 2022 年的大型揭幕准备最终细…

iOS原生项目拥有Flutter热重载极速调试

1. Mac的App Store上下载安装InjectionIII. 2. 打开InjectionIII, Open Project, 选择你的项目目录. 3. 选择的项目会在Open Recent中出现, 保持File Watcher的选项勾选. 4. 在AppDelegate的DidFinishLaunchingWithOptions配置InjectionIII的路径 - (BOOL)application:(UIAp…

python+django勤工助学管理系统vue

目 录 第1章 绪论 1 1.1课题背景 1 1.2 背景意义 1 1.3 研究的内容 2 第2章 相关技术 3 第3章 系统分析 5 3.1可行性分析 5 3.2系统性能分析 6 3.3系统流程分析 6 3.3.1操作流程 6 3.3.2信息添加流程 7 3.3.3信息删除流程 8 第4章 系统设…

周志华 《机器学习初步》 绪论

周志华 《机器学习初步》 绪论 Datawhale2022年12月组队学习 ✌ 文章目录周志华 《机器学习初步》 绪论一.机器学习二.典型的机器学习过程三.计算学习理论PAC模型思考两个问题问题性质角度计算要求的角度四.基本术语五.归纳偏好六.NFL定理哪个算法更好&#xff1f;NFL定理的寓意…

Codeforces Round #837 (Div. 2) A-C

A. Hossam and Combinatorics A题意&#xff1a; 给你n个数&#xff0c;让你求有多少个数对 并且 满足等于数组中最大的绝对值之差。 思路&#xff1a;直接找最大值和最小值&#xff0c;如果最大值和最小值不是一个&#xff0c;那就是最大数的数量乘最小值的数量乘2&#x…

前端基础(一)_前端页面构成

一、前端页面构成 1.HTML(Hypertext Markup Language) Html–超文本标记语言&#xff0c; 结构层由HTML标记语言创建的&#xff0c;负责页面的语义。&#xff08;它包括一系列标签&#xff0c;主要分为块标签和行标签、行内块标签三类&#xff09; 2.CSS(Cascading style sh…

绿色中国馆设计

目 录 1工程概况 1 1.1建筑设计部分 1 1.1.1设计依据 1 1.1.2设计内容、建筑面积、标高 1 1.1.3建筑空间构成 1 1.1.4采光和通风 1 1.1.5防火及安全 2 1.1.6各部分工程构造 2 1.2 结构设计部分 3 1.2.1基本资料 3 1.2.2结构形式和基础形式 3 1.2.3结构尺寸及采用的材料 4 1.2.4…

[oeasy]python0029_放入系统路径_PATH_chmod_程序路径_执行原理

放入路径 回忆上次内容 上次总算可以把 sleep.py 直接执行了 sleep.py文件头部要声明好打开方式 #!/usr/bin/python3用的是 python3 解释 sleep.py 修改 sleep.py 文件 的执行权限 给当前用户增加 执行execute 权限 chmod ux sleep.py 运行./sleep.py成功 但我不想总带着当前路…

[附源码]Python计算机毕业设计SSM基于web的网上订餐系统(程序+LW)

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

Ubuntu18.04安装Carla 记录

官方文档&#xff1a;CARLA Simulator 方式一&#xff1a;简单快速安装&#xff0c;该方式有缺陷。需要使用虚幻引擎编辑器的高级定制和开发选项不可用。 Advanced customization and development options that require use of the Unreal Engine editor are not available b…

【编译原理】第三章部分课后题答案

第 三 章 课 后 习 题 T 3.1 考虑文法 S→(L)∣aL→L,S∣SS \rightarrow (L)\space | \space a\\ L\rightarrow L, S \space | \space S S→(L) ∣ aL→L,S ∣ S (a) 建立句子 (a,(a,a))(a,(a,a))(a,(a,a)) 和 (a,(a,a),(a,a))(a,(a,a),(a,a))(a,(a,a),(a,a)) 的分析树。 见…

SpringMVC学习:三、SpringMVC的请求与响应

4. SpringMVC的请求与响应 4.1 RequestMapping ​ 使用RequestMapping注解可以定义不同的处理器映射规则。 1. URL路径映射: RequestMapping(value“/queryAll”)或RequestMapping("/queryAll”&#xff09; value的值是数组&#xff0c;可以将多个url映射到同一个方法…