【C/C++开发】C++11:左值引用VS右值引用
左值引用VS右值引用
左值引用对于一般的C++程序员再熟悉不过,但对于右值引用(C++0X新特性),就稍微有点不知所云
左值VS右值
在定义变量的时候,经常会用到左值和右值,比如:
int
a = 1;int
b = a + 1;
上面这段代码,a先作为左值,在作为右值。在作为右值的时候,是相当于(原理上等同,但不一定对)
int
tmp(a + 1);int
b(tmp);
中间会先建立一个临时遍历,然后在把临时遍历赋值给b。对于数,只能作为左值,而变量名,即可以作为左值又可以作为右值。(作为左值的时候相当于用该变量的地址,作为右值的时候则相当于使用该变量的内容,这里对于类对象也成立)。
左值引用
用法:Type & 左值引用名 = 左值表达式;
注意点:声明时必须初始化,初始化之后无法在改变;对别名的一切操作都等价于对原来变量的操作。
左值引用在传递参数的时候,和指针特别类似,如以下代码:
int
val = 10;void
fun(int * ptr){ cout<<*ptr<<endl; *ptr += 1; }void
fun(int & value){ cout<<value<<endl; a += 1; }fun(val);
fun(&val);
上面的两种fun()的调用方法,在函数体内的修改都可以引起val的改变。(简单的理解,不一定完全正确:左值引用和指针都相当于是通过地址来访问具体的值,因此可以修改)
const修饰左值引用
int
//此句不合法,因为右值无法赋值给左值引用
& r = val + 1;const
//合法
int& r = val + 1;
解释:资料说c++中临时变量默认const属性,所以只能传给const的引用。规定右值不能绑定到非 const 限定的左值引用。
异常对象另说;如果是右值引用或const左值引用绑定的,那生存期延长为引用;否则到完全表达式结束销毁。还有默认初始化数组元素时延长到数组初始化结束。(摘抄自其网页)
右值引用
在上面的代码中,我们无法建立 int
这样的语法,因为a + 1 此时是作为一个右值来使用的,我们无法把一个右值赋值给一个左值引用。(也就是左值引用相当于把一个变量的地址付给另一个变量,这两个变量可以访问同一个内存,右值仅仅是一个数,而非内存中的某块地址,因此无法把右值复制给左值引用)。
&rb = a + 1;
声明方法:Type && 右值引用名 = 右值表达式;
std::move()的用法
可以直接把左值或者右值转换成右值引用,使用方法:
int
&& rrval = std::move(val);
但是这里需要注意:在调用完std::move之后,不能再使用val,只能使用 rrval,这一点用于基本类型可能没什么直接影响,当应用到类函数的时候,用好std::move 可以减少构造函数数的次数,具体的使用参考下面的std::move比较好的理解
下面说一下自己的理解:
首先是由于STL里面默认的库已经支持右值引用,也有所谓的移动构造函数如下面的形式A
这里不能使用const A&& a,因为需要改变a。移动构造函数主要的用途是,当你不需要在使用一个变量的时候,可以直接通过该构造函数来实现把该变量的数据转换到另一个变量中,省去调用默认的赋值构造或者拷贝构造函数带来额外的开销,如string类在赋值或者拷贝构造函数中会声明char数组来存放数据,然后把原string中的
(A&& a){}
char 数组被析构函数释放,如果a是一个临时变量,则上面的拷贝,析构就是多余的,完全可以把临时变量a中的数据直接 “转移” 到新的变量下面即可。 如下面的程序(摘抄自网页):
#include <iostream>
#include <utility>
#include <vector>
#include <string>
int main()
{
std::string str = "Hello";
std::vector<std::string> v;
//调用常规的拷贝构造函数,新建字符数组,拷贝数据
v.push_back(str);
std::cout << "After copy, str is \"" << str << "\"\n";
//调用移动构造函数,掏空str,掏空后,最好不要使用str
v.push_back(std::move(str));
std::cout << "After move, str is \"" << str << "\"\n";
std::cout << "The contents of the vector are \"" << v[0]
<< "\", \"" << v[1] << "\"\n";
}
总结:
其实这个右值引用主要的用处就是在于配合std::move来实现 “转移语句”A();
//默认构造函数A(const
//拷贝构造函数
A& a);oprator=(const
//赋值构造函数
A& a);A(A&&
//移动构造函数
a);
可以在移动构造函数中实现 把a的数据直接转移到 新的变量b下面,而省去 申请声明一个变量b, 把 copy a->b, 然后释放 a
的空间。
比如,string str = “hello"; 现在str不在使用了,但需要声明一个新的变量表示str, 此时就可以用 string newstr(str::move(str)); 调用移动构造函数,把str下面的内容全部转移到 newstr下面,“掏空”str,这里需要注意掏空str之后,最好就不要在使用str了。(有点啰嗦了)
注释:
赋值构造函数:A & operator = (const A& a); //这里返回A & 是为了进行连等 a1 = a2 = a3,当一个变量已经被定义之后,改变值的时候调用该函数
拷贝构造函数:A(const A&a); 直接在定义声明一个对象的时候,依据另一个对象来构造。
参考链接:
左值右值定义:http://www.cnblogs.com/catch/p/3500678.html
右值表达式VS左值表达式:http://blog.sina.com.cn/s/blog_7fe1e77b01016okx.html
左值引用和右值引用:http://www.linuxidc.com/Linux/2015-02/114056.htm
右值引用:http://blog.csdn.net/zwvista/article/details/12306283
临时对象不能绑定到非const左值引用上:http://blog.csdn.net/liuxialong/article/details/6539717
http://blog.csdn.net/feeltouch/article/details/9789731
std::move用法理解
std::move比较好的解释:http://www.cnblogs.com/chezxiaoqiang/archive/2012/10/24/2736630.html
另外三篇关于std::move 的用法:
上:http://blog.csdn.net/yapian8/article/details/42341307
中:http://blog.csdn.net/yapian8/article/details/42341321
下:http://blog.csdn.net/yapian8/article/details/42341351
【C/C++开发】C++11:左值引用VS右值引用的更多相关文章
- c++ 11 移动语义、std::move 左值、右值、将亡值、纯右值、右值引用
为什么要用移动语义 先看看下面的代码 // rvalue_reference.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #includ ...
- C++ 11 左值,右值,左值引用,右值引用,std::move, std::foward
这篇文章要介绍的内容和标题一致,关于C++ 11中的这几个特性网上介绍的文章很多,看了一些之后想把几个比较关键的点总结记录一下,文章比较长.给出了很多代码示例,都是编译运行测试过的,希望能用这些帮助理 ...
- c++11 左值引用、右值引用
c++11 左值引用.右值引用 #define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <string> #i ...
- 左值与右值,左值引用与右值引用(C++11)
右值引用是解决语义支持提出的 这篇文章要介绍的内容和标题一致,关于C++ 11中的这几个特性网上介绍的文章很多,看了一些之后想把几个比较关键的点总结记录一下,文章比较长.给出了很多代码示例,都是编译运 ...
- C++11的左值引用与右值引用总结
概念 在C++11中,区别表达式是左值或右值可以做这样的总结:当一个对象被用作右值的时候,用的是对象的值(内容):当对象被用作左值的时候,用的是对象的身份(在内存中的位置).左值有持久的状态,而右值要 ...
- C++11左值引用和右值引用
转载:https://www.cnblogs.com/golaxy/p/9212897.html C++11的左值引用与右值引用总结 概念 1.&与&& 对于在C++中,大家 ...
- C++11常用特性介绍——左值引用、右值引用
一.左值.右值 1)左值:可以放在赋值号左侧.可以被赋值的值:左值必须要在内存中有实体. 2)右值:必须放在赋值号右侧.取出值赋值给其它变量:右值可以在内存中也可以在CPU寄存器中. 二.引用 引用是 ...
- C++11 左值引用和右值引用与引用折叠和完美转发
1.左值与右值 最感性的认识. 当然,左值也是可以在右边的. 左值是可以被修改的,右值不能. 当然取地址也是. 生存周期一般左值会比右值的长,一般右值都计算时产生的无名临时对象,存在时间比较短. 下面 ...
- C++的左值,右值,左值引用,右值引用
参考大神链接: https://blog.csdn.net/u012198575/article/details/83142419 1.左值与右值 https://msdn.microsoft.com ...
随机推荐
- iOS 图像渲染原理
http://chuquan.me/2018/09/25/ios-graphics-render-principle/ 通过 图形渲染原理 一文,大致能够了解图形渲染过程中硬件相关的原理.本文将进一步 ...
- POJ3616-Milking Time-(dp)
题意:牛有m个时间段可以挤奶,每个时间段的开始时间,结束时间,挤奶量不尽相同,寄完一次需要休息r时间,求在n时间内如何安排牛挤奶产量最大. 解题: 1.休息r时间,当做结束时间需要+r 2.以结束时间 ...
- Manjaro Linux使用1月滚粗记
每个OIer都有对Linux的向往(雾) 这不,一个月前我便看上了Manjaro,主要原因是因为Manjaro软件包全,安装简便,下面就来说说我退回windows的原因: 1.桌面卡顿,我用的gnom ...
- 部署django到服务器
部署 服务器环境配置 在本地的虚拟环境中,项目根目录下,执行命令收集所有的包 pip freeze > plist.txt 安装并创建虚拟环境,如已创建则跳过此步 sudo apt-get in ...
- 计蒜客 41391.query-二维偏序+树状数组(预处理出来满足情况的gcd) (The Preliminary Contest for ICPC Asia Xuzhou 2019 I.) 2019年徐州网络赛)
query Given a permutation pp of length nn, you are asked to answer mm queries, each query can be rep ...
- 洛谷P3258 [JLOI]2014松鼠的新家
题目 树上差分 树上点差分,注意会出现路径端点多记录的情况,这时需要在最后输出的时候输出子树的差分数组的和-1,而不是在处理原数据的时候减1.并且a[n]不需要糖果,最后也减去就行. #include ...
- Java中的long类型和Long类型比较大小
Java中我们经常要做一些判断,而对于判断的话,用的最多的便是“>”.“==”.“<”的比较,这里我们进行一个Long类型数据和long类型数据的比较大小的讲解. Java中Long和lo ...
- Sequelize 数据类型
Sequelize.STRING // VARCHAR(255)Sequelize.STRING(1234) // VARCHAR(1234)Sequelize.STRING.BINARY // VA ...
- 性能测试-GC问题整理
年轻代与老年代的调优(笔记整理) 几个常见名词 年轻代(young 区)从年轻代空间(包括Eden和Survivor 区域)回收内存被称为 Minor GC空间太小可能导致对象直接进入 old区 .如 ...
- 迁移学习、fine-tune和局部参数恢复
参考:迁移学习——Fine-tune 一.迁移学习 就是把已训练好的模型参数迁移到新的模型来帮助新模型训练. 模型的训练与预测: 深度学习的模型可以划分为 训练 和 预测 两个阶段. 训练 分为两种策 ...