C++11 右值,右值引用,移动构造,移动赋值 |
您所在的位置:网站首页 › c赋值构造函数 › C++11 右值,右值引用,移动构造,移动赋值 |
目录 一、左值,左值引用,右值,右值引用的相关概念: 1. 什么是左值,什么是左值引用? 2. 什么是右值,什么是右值引用? 3. 右值的属性是右值,右值引用的属性是左值 4. 左值引用与右值引用的简单比较: 二、右值引用的作用(使用场景) 左值引用的作用: 左值引用的短板: 右值引用作用1,使用场景1: to_string传值返回,string类的拷贝构造 vs 移动构造 to_string传值返回,string类的拷贝赋值 vs 移动赋值 场景一总结: 右值引用作用2,使用场景2: 三、模板中的万能引用&& 与 完美转发 一、左值,左值引用,右值,右值引用的相关概念: 1. 什么是左值,什么是左值引用?左值是一个表示数据的表达式(如变量名或解引用的指针),左值的特征是可以获取它的地址 + 可以对它赋值,左值可以出现在赋值符号的左边。(右值不能出现在赋值符号的左边)。 有一个例外:const修饰的左值不能出现在赋值符号左边。故,左值最大的特点是是:可以对它取地址。 左值引用就是对左值的引用,给左值取别名。 // 以下的p,b,c,*p都是左值 int* p = new int(0); int b = 1; const int c = 2; *p = 10; // 左值引用: int*& rp = p; int& rb = b; const int& rc = c; int& ri = *p; 2. 什么是右值,什么是右值引用?右值也是一个表示数据的表达式,如:字面常量、表达式返回值,函数返回值(这个不能是左值引 用返回,也就是必须是值返回)... 右值不能出现在赋值符号的左边,可以出现在赋值符号的右边,右值不能取地址。 右值引用就是对右值的引用,给右值取别名。 赋值运算符的左侧必须为左值。“=”: 左操作数必须为左值。 右值可以分为两种:1. 内置类型右值-纯右值 2. 自定义类型右值-将亡值 double x = 10.1, y = 20.2; // 右值示例: 10; x+y; fmin(x, y); // 值返回 // 右值引用示例: int&& ri = 10; double&& rd = x + y; double&& rd2 = fmin(x, y); 3. 右值的属性是右值,右值引用的属性是左值右值不能取地址,比如10不能取地址。但是右值引用可以取地址,且可以给右值引用赋值。也就是 int&& ri = 10; &ri; ri = 20; 是合法的。因为给右值取别名后,会导致右值引用被存储在特定位置,属性变为左值。 右值引用的属性是左值。const 右值引用的属性是const 左值。因为左值可以取地址,可以赋值。因此右值引用可以取地址,可以赋值。const 右值引用可以取地址,不能赋值。 4. 左值引用与右值引用的简单比较:1. 左值引用只能引用左值,不能引用右值。 const 左值引用既能引用左值,也能引用右值。 2. 右值引用只能引用右值,不能引用左值。 但是右值引用可以引用move后的左值。(这个其实就是move函数的作用,std::move函数可以将左值强制转化为右值引用,返回这个左值的右值引用) 二、右值引用的作用(使用场景)既然左值引用可以引用左值,且const 左值引用还可以引用右值,那么右值引用的作用是什么呢?探究C++11引入右值引用的作用之前,先来探究左值引用的作用,以及左值引用的短板,从而理解右值引用的作用。 左值引用的作用:1. 左值引用做函数参数。 a. 引用传参,减少拷贝,提高效率。最典型的比如拷贝构造函数,operator=(),以对象为模板拷贝构造一个新的对象,这里传引用可以减少传参时的拷贝,提高效率。 b. 做输出型参数,代替C语言的传指针。 2. 左值引用做函数返回值。 a. 传引用做返回值,减少拷贝,提高效率。(我们知道,传值返回是要拷贝构造一个临时对象的(编译器不优化或不能优化的情况下),这里会降低效率。) b. 传引用返回,用于修改返回对象。最典型的比如 vector的operator[]。很多堆区开辟的对象,都可以采用传引用返回的方式,使程序使用对一个对象进行处理。 重新审视拷贝构造函数和重载赋值运算符函数的参数,为什么要定为 const Type& t 一方面,传引用可以提高效率,减少拷贝。这里加const的作用可以防止修改左值引用。另一方面是,const 左值引用才能引用右值。否则这个拷贝构造函数或operator=不能以右值为实参。也就是 T t(T()); 将报错,因为左值引用不能引用临时对象的这种右值。 左值引用的短板:若一个对象在堆区,则函数可以传引用返回。但是,对于函数内的局部临时对象,函数返回后,出了作用域,局部对象就会销毁,是不可以传引用返回的。 而如果采用值返回,则会发生拷贝构造,若这个对象不是内置类型,而是深拷贝的自定义类型,则发生深拷贝还会降低效率。 对于自定义类型的右值,我们称之为将亡值,也就是函数内的局部临时对象。 右值引用作用1,使用场景1:C++11中,右值引用的一个重要功能,就是解决函数值返回涉及深拷贝的局部临时对象的低效率问题。解决方法为:利用右值引用为自定义类型实现移动构造和移动赋值成员函数。 to_string传值返回,string类的拷贝构造 vs 移动构造比如,我们模拟实现一个string类。则,yzl::string to_string(int val); 函数,用于将整型转为我们实现的string类型,此处必须传值返回,因为函数内创建的局部string对象出了函数作用域就会销毁。 yzl::string to_string(int val) { yzl::string str; // ... return str; // 此str的属性为右值 } void func() { yzl::string s = yzl::to_string(10); } // 以模拟实现string类为例的移动构造和移动赋值实现。 // 移动构造 string(string &&s) : _str(nullptr), _size(0), _capacity(0) { cout |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |