左值与右值

在C语言中,左值和右值一般有两种区分的方法。可以出现在赋值符号“=”的两边的值为左值,只能出现在赋值符号“=”的右边的值为右值;还有一种说法是能取地址的为左值,不能取地址的为右值。但是这两种说法并非完全正确

void test()
{int a = 10;int b = a;//ok a为左值10 = a; //error 10为右值int* pa = &a;//okint* pi = &10;//error
}

而在C++中,右值有3种变量,分别为常量临时变量/匿名变量将亡值;其他的变量都为左值

将亡值就是声明即将结束的变量

int fun(int a)
{return a;//将亡值
}

C++引入右值的原因

  1. 实现移动语义(移动构造和移动赋值)
  2. 给中间临时变量取名字
  3. 实现完美转发

左值引用和右值引用

左值引用就是我们平时用的引用,左值引用就是在类型后面加&,则定义该变量为引用类型。左值引用及可以引用左值,也可以引用右值

void test()
{int a = 10;int& ra = a;//引用左值const int& ri = 10;//引用右值
}

右值引用则需要在变量类型加上&&,则为右值引用。右值引用不能引用左值,只能引用右值

void test()
{int a = 10;int&& rri = 10;//okint&& rra = a;//error;
}

右值引用的作用

在我们平时写的代码中,常常为有创建拷贝以及释放空间的开销,而C++是一门追求极致性能的语言,所以会尽可能在保持原有特性上增强性能。而引入右值引用,目的就是为了在某些特定场景下提高代码运行的效率—通过不进行深拷贝来提高代码拷贝效率
我们先来看看自己实现的string类

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;class String {public:String(const char* str = "") {if (nullptr == str) str = "";_str = new char[strlen(str) + 1]; strcpy(_str, str);}String(const String& s) : _str(new char[strlen(s._str) + 1]){strcpy(_str, s._str);cout << "String(const String&)" << endl;}String& operator=(const String& s) {if (this != &s) {char* pTemp = new char[strlen(s._str) + 1]; strcpy(pTemp, s._str); delete[] _str; _str = pTemp;cout << "String& operator=(const String&)" << endl;} return *this;}String operator+(const String& s) {char* pTemp = new char[strlen(_str) + strlen(s._str) + 1]; strcpy(pTemp, _str); strcpy(pTemp + strlen(_str), s._str); String strRet(pTemp);return strRet;}~String() { if (_str) delete[] _str; }
private: char* _str;
};
void test() {String s1("hello"); String s2("world"); String s3(s1 + s2);
}

在测试代码中,要创建s3会经历很多次的申请空间,第一是先要先将s1和s2进行+操作,在operator+函数中,最后要将空间赋值给strRet是时会进行拷贝,然后在返回strRet时也会进行一次拷贝,然后将拷贝的临时变量用来创建s3时又要调用拷贝构造。而拷贝构造是深拷贝,每次调用都需要开辟空间和花费时间

但是在vs中编译器会进行优化。将返回值那一步拷贝过程去掉


但是在C++11中,引入了 右值引用,还可以有优化的空间。也就是s3也不需要开辟新的空间,直接利用strRet的原有资源。将strRet中的资源移动到s3中

 String(String&& s) :_str(s._str)//直接指向strRet的资源{s._str = nullptr;//置其为空,防止二次释放cout << "String(String&&)" << endl;}

在右值引用的拷贝构造中并没有申请新的空间。这两个拷贝构造可以共存,大部分情况下是会调用左值引用的拷贝构造,只有以上情况,也就是临时变量,只有为右值时才会调用右值引用的拷贝构造。
同理,重载赋值运算符也可以使用右值引用

 String& operator=(String&& s) {if (this != &s) {delete[] _str;_str = s._str;s._str = nullptr;cout << "String& operator=(String&&)" << endl;} return *this;}


move----将左值属性的变量修改为右值

void test()
{int a = 10;int&& rra = move(a);//ok
}

完美转发----在函数传递过程中保持变量的原有属性

void Fun(int& x) { cout << "左值引用" << endl; }
void Fun(int&& x) { cout << "右值引用" << endl; }
void Fun(const int& x) { cout << "const类型的左值引用" << endl; }
void Fun(const int&& x) { cout << "const类型的右值引用" << endl; }
template<typename T>
void PerfectForward(T&& t) //如果是左值则为左值引用
{ Fun(std::forward<T>(t)); //完美转发std::forward<T>(name)
}
void test() {PerfectForward(10); // 右值引用int a = 4;PerfectForward(a); // 左值引用PerfectForward(std::move(a)); // 右值引用const int b = 8;PerfectForward(b); // const类型的左值引用PerfectForward(std::move(b)); // const类型的右值引用
}

C++ C++11新特性--右值引用相关推荐

  1. C++11新特性 右值引用与移动语义

    右值引用作用是可以减少内存拷贝次数,从而优化性能. 首先,什么是右值?右值是一个与左值相区分的概念.左值是:既能出现在等号左边也能出现在等号右边的变量或表达式,比如int a = 5,那么a就是一个左 ...

  2. C++11 标准新特性: 右值引用与转移语义(点评)

    <<C++11 标准新特性: 右值引用与转移语义>> 原文地址如下 http://www.ibm.com/developerworks/cn/aix/library/1307_ ...

  3. std::move C++11 标准新特性: 右值引用与转移语义

    新特性的目的 右值引用 (Rvalue Referene) 是 C++ 新标准 (C++11, 11 代表 2011 年 ) 中引入的新特性 , 它实现了转移语义 (Move Sementics) 和 ...

  4. C++11 标准新特性: 右值引用与转移语义

    原文地址 http://www.ibm.com/developerworks/cn/aix/library/1307_lisl_c11/ C++ 的新标准 C++11 已经发布一段时间了.本文介绍了新 ...

  5. 【转】C++11 标准新特性: 右值引用与转移语义

    VS2013出来了,对于C++来说,最大的改变莫过于对于C++11新特性的支持,在网上搜了一下C++11的介绍,发现这篇文章非常不错,分享给大家同时自己作为存档. 原文地址:http://www.ib ...

  6. C++11中的右值引用

    http://www.cnblogs.com/yanqi0124/p/4723698.html 在C++98中有左值和右值的概念,不过这两个概念对于很多程序员并不关心,因为不知道这两个概念照样可以写出 ...

  7. C++ 11 中的右值引用

    C++ 11 中的右值引用 右值引用的功能 首先,我并不介绍什么是右值引用,而是以一个例子里来介绍一下右值引用的功能: #include <iostream>     #include & ...

  8. C++11中的右值引用(对比左值引用和常引用)、移动构造函数和引用标识符

    Hello!各位同学们大家好!逗比老师最近说起来还是挺尴尬的,为什么这么说呢?因为以前我对自己的C++水平还是相当自信的,经常以"精通"来自我评价.但是最近发现自己好像对C++11 ...

  9. C++11标准之右值引用(ravalue reference)

    C++11标准之右值引用(ravalue reference) 1.右值引用引入的背景 临时对象的产生和拷贝所带来的效率折损,一直是C++所为人诟病的问题.但是C++标准允许编译器对于临时对象的产生具 ...

最新文章

  1. 论文被scoop(抢先发表)是怎样一种体验?
  2. A English version for my blog start.
  3. 2019第一篇万字长文!30+家一线投资机构已出投资新策略...
  4. 买卖股票的最好时机二Python解法
  5. rest api_REST API的演变
  6. Ubuntu下安装uwsgi报错的解决方案
  7. 超级详细的Oracle安装图文详解!手把手教会您从下载到安装!
  8. i5功耗最低的cpu_探寻低电压CPU性能 i5-3330S对比测试
  9. nuxt SSR部署到iis7方案
  10. Windows编程之钩子程序
  11. qt在linux下编译资源文件,linux下Qt qrc文件的编写与应用
  12. 添加最顶层js广告_js实现网站最上边可关闭的浮动广告条代码
  13. 解决报错:错误使用 xlsread未找到工作表 ‘sheet1‘
  14. Allergo 无法修改单位
  15. STM32F103驱动THM3060读取二代身份证
  16. 常用第三方支付和聚合支付介绍
  17. Cannot find current proxy: Set ‘exposeProxy‘ property on Advised to ‘true‘ to make it available
  18. 小白猿笔记Day6(面向对象)
  19. UML系列——时序图(顺序图)
  20. 上帝在基督里赦免了所有人的罪

热门文章

  1. jq获取下拉列表_jQuery下拉框操作系列$(option:selected,this) (锋利的jQuery)
  2. mysql innodb 事务_MySQL学习笔记之InnoDB事务实现
  3. linux qt usb转串口通信,centos7 Qt USB转串口通信
  4. u盘efi安装linux6.5,CentOS6.5安装的UEFI-GPT回退为MBR引导详解
  5. cm201–2刷机短接教程_Jetson TX2 刷机教程(JetPack4.2版本)
  6. 基于JAVA+SpringBoot+Mybatis+MYSQL的美食分享网站
  7. 如何利用计算机实现非线性转换,基于cass数控绕线机非线性算法的设计与实现-计算机应用技术专业论文.docx...
  8. curl 没有到主机的路由_安装RaspAP将树莓派变身为无线路由器
  9. BZOJ4698 SDOI2008Sandy的卡片(后缀自动机)
  10. SQL_server 数据库备份信息查看