左值与右值

C++ 引用详解

我与影子孤独终老i 提交于 2020-02-11 12:00:07
引用是C++引入的新类型,是对一块内存空间起的一个别名,主要分为 左值引用 、 常量左值引用 和 右值引用 三种。C++语言标准规定,一个引用不是左值引用就是右值引用。其中, 函数引用 是一种特殊的左值常量引用; 万能引用(universal reference) 是一种特殊的引用类型,既可以表示左值引用,也可以表示右值引用,具体的引用类型最终会由编译器决定,判断依据是 引用折叠(reference collasping) 。 一、左值引用 一句话总结:左值引用是一级指针的语法糖 。只有左值才能绑定到左值引用上。 int &a = 0; // a是int*的语法糖。 int *b = nullptr; int *&b_ref = b; // b_ref是int**的语法糖。 大量的资料表示,编译器中的引用是以指针实现的。然而,左值引用必须要初始化后才能使用,否则会引发编译错误(这与指针不同,野指针或者空指针即便不初始化也可以通过编译),所以可以这样理解: 如果代码通过了编译,那么引用的对象一定是可用的 。然而,凡事有利必有弊,这样的特性也会导致问题。最典型的问题是: 引用无法表示空值 。例如,有些对象的成员并不是必需的,在复制文件时并不一定需要提供进度通知,应该由用户自行决定,而不是强制要求提供: class file_copier { progress& _progress; /

C++知识点汇总文档

蓝咒 提交于 2020-01-29 03:14:26
C++知识点汇总文档 持续更新 朝花夕拾. 不写下来, 仿佛一切都没了见证. 编程来源于生活, 无非是对现实的抽象. 整理这份文档的时候我才发现, 自己对C++的了解无非是冰山一角 另, C++11真的 太恐怖了 , 新"特性"真的是"恐怖如斯" 另注: 本人才疏学浅, 难免有错漏之处, 还望不吝赐教 1.基本概念 内存管理 C++中的内存划分(内容来自 博客 ): 堆 由用户使用new delete关键字管理的内存区域 栈 栈中用来存放临时变量, 比如函数中的局部变量, 在代码块结束时会自动清除 自由存储区 由malloc等分配的内存块, 他和堆是十分相似的, 不过它是用free来结束自己的生命的 全局/静态存储区 全局变量和静态变量被分配到同一块内存中 常量存储区 比较特殊的存储区, 他们里面存放的是常量(不太了解, 有空扫下盲) new 关键字 用来在内存(堆)中开辟一块空间, 用户获得一个指向内存中目标位置的指针 用法 参考示例 //申请一块指向单个int对象的内存, 并将值初始化为"5" int *ptr_0 = new int(5); //申请一块指向5个连续int类型对象的内存 //使用C++11统一的花括号初始化, 直观地对内存进行初始化 int * ptr_1 = new int[5]{1,2,3,4,5}; delete 关键字 删除 使用new申请的内存 用法

右值引用与移动构造函数

不羁岁月 提交于 2020-01-12 19:26:15
右值引用与移动构造函数 文章目录 右值引用与移动构造函数 左值(lvalue)、右值(rvalue)、xvalue、prvalue、glvalue 定义 一些问题 左值引用与右值引用 测试 移动构造函数、移动赋值 Reference 左值(lvalue)、右值(rvalue)、xvalue、prvalue、glvalue 定义 c++primer ​ 这两个名词是从C语言继承过来的,原本是为了帮助记忆:左值可以位于赋值语句的左侧,右值则不能( 区别不是这么简单,这里的只是为了方便记忆 )。C++的表达式要么是右值(rvalue),要么是左值(lvalue)。 C++中,一个左值表达式的求值结果是一个对象或者一个函数(然而以常量对象为代表的某些左值实际上不能作为赋值语句的左侧运算对象)。此外,虽然某些表达式的求值结果是对象,但它们是右值而非左值。简单归纳:当一个对象被用作右值时,用的是对象的值(内容);当对象被用作左值的时候,用的是对象的身份(在内存中的位置)。 1 (《C++ primer 5th edition》) 官方文档 C++11在官方文档上 ^2 ,说明了表达式的值类型。如下所示。 官方文档(官方文档 ^2 3.10节。这样解释: An lvalue (之所以这样称它,因为过去左值可以出现在赋值表达式的左边)表示了一个函数或一个对象。(比如,如果E是一个指针类型,那么

[译]详解C++右值引用

拈花ヽ惹草 提交于 2019-12-09 14:33:49
C++0x标准出来很长时间了,引入了很多牛逼的特性 [1] 。其中一个便是右值引用,Thomas Becker的文章 [2] 很全面的介绍了这个特性,读后有如醍醐灌顶,翻译在此以便深入理解。 目录 概述 move语义 右值引用 强制move语义 右值引用是右值吗? move语义与编译器优化 完美转发:问题 完美转发:解决方案 Rvalue References And Exceptions The Case of the Implicit Move Acknowledgments and Further Reading 概述 右值引用是由C++0x标准引入c++的一个令人难以捉摸的特性。我曾偶尔听到过有c++领域的大牛这么说: 每次我想抓住右值引用的时候,它总能从我手里跑掉。 想把右值引用装进脑袋实在太难了。 我不得不教别人右值引用,这太可怕了。 右值引用恶心的地方在于,当你看到它的时候根本不知道它的存在有什么意义,它是用来解决什么问题的。所以我不会马上介绍什么是右值引用。更好的方式是从它将解决的问题入手,然后讲述右值引用是如何解决这些问题的。这样,右值引用的定义才会看起来合理和自然。 右值引用至少解决了这两个问题: 实现move语义 完美转发(Perfect forwarding) 如果你不懂这两个问题,别担心,后面会详细地介绍。我们会从move语义开始

看完这个你还不理解右值引用和移动构造 你就可以来咬我(上)

≡放荡痞女 提交于 2019-12-09 12:22:35
C++ 右值引用 & 新特性 C++ 11中引入的一个非常重要的概念就是右值引用。理解右值引用是学习“移动语义”(move semantics)的基础。而要理解右值引用,就必须先区分左值与右值。 对左值和右值的一个最常见的误解是:等号左边的就是左值,等号右边的就是右值。左值和右值都是针对表达式而言的,左值是指表达式结束后依然存在的持久对象,右值是指表达式结束时就不再存在的临时对象。一个区分左值与右值的便捷方法是:看能不能对表达式取地址,如果能,则为左值,否则为右值。下面给出一些例子来进行说明。 int a = 10; int b = 20; int *pFlag = &a; vector<int> vctTemp; vctTemp.push_back(1); string str1 = "hello "; string str2 = "world"; const int &m = 1; 请问,a,b, a+b, a++, ++a, pFlag, *pFlag, vctTemp[0], 100, string("hello"), str1, str1+str2, m分别是左值还是右值? a和b都是持久对象(可以对其取地址),是左值; a+b是临时对象(不可以对其取地址),是右值; a++是先取出持久对象a的一份拷贝,再使持久对象a的值加1,最后返回那份拷贝,而那份拷贝是临时对象

右值与移动语义

假如想象 提交于 2019-12-05 23:33:39
一、Overloading Rules for Rvalue and Lvalue References 左值引用和右值引用的优先级问题 1、如果只实现了左值引用,那么不能传入右值和const。 void f(X& x); 2、如果只实现了void f(const X& x); 可以接收左值和右值。 3、如果同时实现了void f([const] X& x) 和 void f(X &&x),右值会优先选择移动语义。 总结:如果你的类只提供了拷贝语义,没有提供移动,那么std::move()就调用拷贝操作。 二、没必要 而且不应该为返回值调用std::move操作。 X f(){ X x; ... return x; } 编译器的行为如下: 优先级最高的是 1、如果X有自定义的移动或者拷贝构造,编译器会选择抹掉拷贝或移动构造。具名返回值优化。 如果编译器没有消除构造,那么 2、如果X有移动构造,就会调用移动构造。 3、如果X有拷贝构造,调用拷贝构造。 4、调用缺省的?内存拷贝? 3、返回local object的引用是错误的。 X&& foo () { X x; ... return x; // ERROR: returns reference to nonexisting object } 来源: https://www.cnblogs.com/buddho/p/11950487

左值与右值

混江龙づ霸主 提交于 2019-12-04 13:31:36
左值表达式与右值表达式 一个表达式的求值结果如果是左值,就是左值表达式。如果是右值,就是右值表达式 ++i 左值表达式 i++ 右值表达式 来源: https://www.cnblogs.com/smallredness/p/11867846.html

第一章 数组与指针概念剖析

情到浓时终转凉″ 提交于 2019-12-04 07:41:25
数组与指针生来就是双胞胎,多数人就是从数组的学习开始指针的旅程的。在学习的过程中,很自然就会经常听到或见到关于数组与指针的各种各样的看法,下面我节选一些在各种论坛和文章里经常见到的文字: “一维数组是一级指针” “二维数组是二级指针” “数组名是一个常量指针” “数组名是一个指针常量” ........................ 这些文字看起来非常熟悉吧?类似的文字还有许多。不过非常遗憾,这些文字都是错误的,实际上数组名永远都不是指针!这个结论也许会让你震惊,但它的确是事实。但是,在论述这个问题之前,首先需要解决两个问题:什么是指针?什么是数组?这是本章的主要内容,数组名是否指针这个问题留在第二章进行讨论。看到这里,也许有人心里就会嘀咕了,这么简单的问题还需要说吗?int *p, a[10];不就是指针和数组吗?但是,笔者在过往的讨论过程中,还真的发现有不少人对这两个概念远非清晰,这会妨碍对后面内容的理解,所以还是有必要先讨论一下。 什么是指针?一种普遍存在的理解是,把指针变量理解成就是指针,这种理解是片面的,指针变量只是指针的其中一种形态,但指针并不仅仅只有指针变量。一个指针,包含了两方面的涵义:实体(entity)和类型。标准是这样描述指针类型的: 6.2.5 Types A pointer type may be derived from a function type

C++左值与右值

我是研究僧i 提交于 2019-12-02 19:14:29
在C++11中所有的值必属于左值、右值两者之一,右值又可以细分为纯右值、将亡值。在C++11中可以取地址的、有名字的就是左值,反之,不能取地址的、没有名字的就是右值(将亡值或纯右值)。举个例子,int a = b+c, a 就是左值,其有变量名为a,通过&a可以获取该变量的地址;表达式b+c、函数int func()的返回值是右值,在其被赋值给某一变量前,我们不能通过变量名找到它,&(b+c)这样的操作则不会通过编译。 1 int &a = 2; // 左值引用绑定到右值,编译失败 2 3 int b = 2; // 非常量左值 4 const int &c = b; // 常量左值引用绑定到非常量左值,编译通过 5 const int d = 2; // 常量左值 6 const int &e = c; // 常量左值引用绑定到常量左值,编译通过 7 const int &b =2; // 常量左值引用绑定到右值,编程通过 int a = 1; int &&r1 = a; // 编译失败 int &&r2 = std::move(a); //将左值转变为右值编译通过 来源: https://www.cnblogs.com/chenguifeng/p/11759875.html

左值与右值

眉间皱痕 提交于 2019-12-02 08:01:35
通常来说有名字的变量就是左值(如上面例子中的 a, b),而由运算操作(加减乘除,函数调用返回值等)所产生的中间结果(没有名字)就是右值 左值就是在程序中能够寻值的东西,右值就是没法取到它的地址的东西(不完全准确) 记这个: 在C++之中的变量只有左值与右值两种:   凡是可以取地址的变量就是左值,   而没有名字的临时变量,字面量就是右值” https://www.cnblogs.com/catch/p/3500678.html 来源: https://www.cnblogs.com/WHUT-Simon/p/11736331.html