左值与右值

右值引用与转移语义

…衆ロ難τιáo~ 提交于 2019-11-30 23:05:24
右值引用与转移语义 参考: 右值引用与转移语义 新特性的目的 右值引用 (Rvalue Referene) 是 C++ 新标准 (C++11, 11 代表 2011 年 ) 中引入的新特性 , 它实现了转移语义 (Move Sementics) 和精确传递 (Perfect Forwarding)。它的主要目的有两个方面: 消除两个对象交互时不必要的对象拷贝,节省运算存储资源,提高效率。 能够更简洁明确地定义泛型函数。 左值与右值的定义 C++( 包括 C) 中所有的表达式和变量要么是左值,要么是右值。通俗的左值的定义就是非临时对象,那些可以在多条语句中使用的对象。所有的变量都满足这个定义,在多条代码中都可以使用,都是左值。右值是指临时的对象,它们只在当前的语句中有效。 左值和右值的语法符号 左值的声明符号为”&”, 为了和左值区分,右值的声明符号为”&&”。 转移语义的定义 右值引用是用来支持转移语义的。转移语义可以将资源 ( 堆,系统对象等 ) 从一个对象转移到另一个对象,这样能够减少不必要的临时对象的创建、拷贝以及销毁,能够大幅度提高 C++ 应用程序的性能。临时对象的维护 ( 创建和销毁 ) 对性能有严重影响。 转移语义是和拷贝语义相对的,可以类比文件的剪切与拷贝,当我们将文件从一个目录拷贝到另一个目录时,速度比剪切慢很多。 通过转移语义

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

∥☆過路亽.° 提交于 2019-11-30 12:33:13
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-11-30 04:19:51
地址与变量名 变量名是贴在地址上的标签,供用户操作。 在编译结束后变量名就不存在了。 对变量名操作,实际上是对地址上的数据进行操作。 左值与右值 int a, b; const int c = 42; b = c; a = b; a为左值,b、c为右值 大部分变量既可以作为左值也可以作为右值 const 关键字限定的变量只能作为右值 来源: https://www.cnblogs.com/Linkunpeng/p/11558941.html

指针

*爱你&永不变心* 提交于 2019-11-29 15:51:20
内存和地址 内存其实就是一组有序字节组成的数组,数组中,每个字节大小固定,都是 8bit。对这些连续的字节从 0 开始进行编号,每个字节都有唯一的一个编号,这个编号就是内存地址。示意如下图: 指针变量保存的就是这些编号,也即内存地址。 地址与内容 我们只要知道内存地址,就可以访问这个地址的值,但是这种方法实在笨拙,于是便用变量名来代替地址: 名字与内存之间的关联仅仅只是编译器实现的,采用变量名的方式能够方便的记住地址,但是硬件仍然通过地址访问内存位置。 值和类型 考虑下面的32位值: ‭01100111011011000110111101100010‬ 对于这些位的解释可以分为很多种: 类型 值 1个32位数 1735159650 2个16位数 26476和28514 4个字符 glob 浮点数 1.116533e24 机器指令 beg.+110和ble.+102 可见: 不能简单地通过检查一个值的位来判断值的类型,而应该根据它的使用方式来判断 。 使用指针的优势 在C语言中,指针的使用非常广泛,因为使用指针往往可以生成更高效、更紧凑的代码。总的来说,使用指针有如下好处: 指针的使用使得不同区域的代码可以轻易的共享内存数据,这样可以使程序更为快速高效。 C语言中一些复杂的数据结构往往需要使用指针来构建,如链表、二叉树等。 C语言是传值调用,而有些操作传值调用是无法完成的

C++ 11的移动语义

拟墨画扇 提交于 2019-11-28 04:19:54
目录 可拷贝和可移动的概念 移动构造函数和移动赋值函数 小结移动构造和移动赋值 std::move() 使用 std::move 实现一个高效的 swap 函数 Move and swap 技巧 参考 可拷贝和可移动的概念 在面向对象中,有的类是可以拷贝的,例如车、房等他们的属性是可以复制的,可以调用拷贝构造函数,有点类的对象则是独一无二的,或者类的资源是独一无二的,比如 IO 、 std::unique_ptr等,他们不可以复制,但是可以把资源交出所有权给新的对象,称为可以移动的。 C++11最重要的一个改进之一就是引入了move语义,这样在一些对象的构造时可以获取到已有的资源(如内存)而不需要通过拷贝,申请新的内存,这样移动而非拷贝将会大幅度提升性能。例如有些右值即将消亡析构,这个时候我们用移动构造函数可以接管他们的资源。 移动构造函数和移动赋值函数 考虑这样一个类A,里面的成员i 具有一个500的堆数组 #include <iostream> #include <cstring> using namespace std; class A{ public: A():i(new int[500]){ cout<<"class A construct!"<<endl; } A(const A &a):i(new int[500]){ memcpy(a.i,i,500*sizeof

C++ 11的右值引用

≡放荡痞女 提交于 2019-11-27 04:11:47
目录 一、问题导入 二、右值和右值引用 2.1 左值(lvalue)和右值(rvalue) 2.2 左值引用和右值引用 总结 参考资料 C++11 引入了 std::move 语义、右值引用、移动构造和完美转发这些特性。由于这部分篇幅比较长,分为3篇来进行阐述。 在了解这些特性之前,我们先来引入一些问题。 一、问题导入 函数返回值是传值的时候发生几次对象构造、几次拷贝? 函数的形参是值传递的时候发生几次对象构造? 让我们先来看一段代码, // main.cpp #include <iostream> using namespace std; class A{ public: A(){ cout<<"class A construct!"<<endl; } A(const A&){ cout<<"class A copy!"<<endl; } A& operator=(const A&){ cout<<"assignment called!"<<endl; } ~A(){ cout<<"class A destruct!"<<endl; } }; A get_A_value(){ return A(); } int main(){ A a = get_A_value(); return 0; } 使用 g++ 编译;注意使用 -fno-elide-constructors

第15课 完美转发(std::forward)

浪尽此生 提交于 2019-11-26 14:58:06
一. 理解引用折叠   (一)引用折叠   1. 在C++中, “引用的引用”是非法的 。像auto& &rx = x;(注意两个&之间有空格)像这种直接定义引用的引用是不合法的,但是编译器在通过类型别名或模板参数推导等语境中,会间接定义出“引用的引用”,这时引用会形成“折叠”。   2. 引用折叠 会发生在 模板实例化、auto类型推导、创建和运用typedef和别名声明、以及decltype语境中 。 (二)引用折叠规则   1. 两条规则     (1)所有 右值引用折叠到右值引用上仍然是一个右值引用 。如X&& &&折叠为X&&。     (2)所有的其他引用类型之间的折叠都将变成左值引用。如X& &, X& &&, X&& &折叠为X&。可见 左值引用会传染,沾上一个左值引用就变左值引用了 。 根本原因:在一处声明为左值,就说明该对象为持久对象,编译器就必须保证此对象可靠(左值) 。   2. 利用引用折叠进行万能引用初始化类型推导     (1)当万能引用(T&& param)绑定到左值时,由于万能引用也是一个引用,而左值只能绑定到左值引用。因此,T会被推导为T&类型。从而param的类型为T& &&,引用折叠后的类型为T&。     (2)当万能引用(T&& param)绑定到右值时,同理万能引用是一个引用,而右值只能绑定到右值引用上,故T会被推导为T类型