左值引用和右值引用随笔

左值引用VS右值引用

左值引用对于通常的C++程序员再熟悉不过,但对于右值引用(C++0X新特性),就稍微有点不知所云html

左值VS右值

在定义变量的时候,常常会用到左值和右值,好比:
int a = 1;
int b = a + 1;linux

上面这段代码,a先做为左值,在做为右值。在做为右值的时候,是至关于(原理上等同,但不必定对)ios

int tmp(a + 1);
int b(tmp);c++

中间会先创建一个临时遍历,而后在把临时遍历赋值给b。对于数,只能做为左值,而变量名,便可以做为左值又能够做为右值。(做为左值的时候至关于用该变量的地址,做为右值的时候则至关于使用该变量的内容,这里对于类对象也成立)。程序员

左值引用

用法:Type & 左值引用名 = 左值表达式;api

注意点:声明时必须初始化,初始化以后没法在改变;对别名的一切操做都等价于对原来变量的操做。数组

左值引用在传递参数的时候,和指针特别相似,如如下代码:函数

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);.net

上面的两种fun()的调用方法,在函数体内的修改均可以引发val的改变。(简单的理解,不必定彻底正确:左值引用和指针都至关因而经过地址来访问具体的值,所以能够修改)指针

const修饰左值引用

int & r = val + 1; //此句不合法,由于右值没法赋值给左值引用
const int& r = val + 1;//合法

解释:资料说c++中临时变量默认const属性,因此只能传给const的引用。规定右值不能绑定到非 const 限定的左值引用。
异常对象另说;若是是右值引用或const左值引用绑定的,那生存期延长为引用;不然到彻底表达式结束销毁。还有默认初始化数组元素时延长到数组初始化结束。(摘抄自其网页)

右值引用

在上面的代码中,咱们没法创建 int &rb = a + 1; 这样的语法,由于a + 1 此时是做为一个右值来使用的,咱们没法把一个右值赋值给一个左值引用。(也就是左值引用至关于把一个变量的地址付给另外一个变量,这两个变量能够访问同一个内存,右值仅仅是一个数,而非内存中的某块地址,所以没法把右值复制给左值引用)。

声明方法:Type && 右值引用名 = 右值表达式;

std::move()的用法

能够直接把左值或者右值转换成右值引用,使用方法:

int && rrval = std::move(val);

可是这里须要注意:在调用完std::move以后,不能再使用val,只能使用 rrval,这一点用于基本类型可能没什么直接影响,当应用到类函数的时候,用好std::move 能够减小构造函数数的次数,具体的使用参考下面的std::move比较好的理解
下面说一下本身的理解:
    首先是因为STL里面默认的库已经支持右值引用,也有所谓的移动构造函数以下面的形式A (A&& a){} 这里不能使用const A&& a,由于须要改变a。移动构造函数主要的用途是,当你不须要在使用一个变量的时候,能够直接经过该构造函数来实现把该变量的数据转换到另外一个变量中,省去调用默认的赋值构造或者拷贝构造函数带来额外的开销,如string类在赋值或者拷贝构造函数中会声明char数组来存放数据,而后把原string中的 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

相关文章
相关标签/搜索