zoukankan      html  css  js  c++  java
  • [转] c++11 int&& 右值引用

    [转自 http://blog.csdn.net/yuanwang1986/article/details/8666459 ]

    C++ 11中引入的右值引用正好可用于标识一个非常量右值。C++ 11中用&表示左值引用,用&&表示右值引用,如:

    int &&a = 10

    右值引用根据其修饰符的不同,也可以分为非常量右值引用常量右值引用

    C++ 11中引入的一个非常重要的概念就是右值引用。理解右值引用是学习“移动语义”(move semantics)的基础。而要理解右值引用,就必须先区分左值与右值。

    对左值和右值的一个最常见的误解是:等号左边的就是左值,等号右边的就是右值。左值和右值都是针对表达式而言的,左值是指表达式结束后依然存在的持久对象,右值是指表达式结束时就不再存在的临时对象。一个区分左值与右值的便捷方法是:看能不能对表达式取地址,如果能,则为左值,否则为右值。下面给出一些例子来进行说明。

    1 int a = 10  
    2 int b = 20  
    3 int *pFlag = &a;  
    4 vector<int> vctTemp;  
    5 vctTemp.push_back(1);  
    6 string str1 = "hello "  
    7 string str2 = "world"  
    8 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,最后返回那份拷贝,而那份拷贝是临时对象(不可以对其取地址),故其是右值;

    ++a则是使持久对象a的值加1,并返回那个持久对象a本身(可以对其取地址),故其是左值;

    pFlag和*pFlag都是持久对象(可以对其取地址),是左值;

    vctTemp[0]调用了重载的[]操作符,而[]操作符返回的是一个int &,为持久对象(可以对其取地址),是左值;

    100和string("hello")是临时对象(不可以对其取地址),是右值;

    str1是持久对象(可以对其取地址),是左值;

    str1+str2是调用了+操作符,而+操作符返回的是一个string(不可以对其取地址),故其为右值;

    m是一个常量引用,引用到一个右值,但引用本身是一个持久对象(可以对其取地址),为左值。

    区分清楚了左值与右值,我们再来看看左值引用。左值引用根据其修饰符的不同,可以分为非常量左值引用和常量左值引用。

    非常量左值引用只能绑定到非常量左值,不能绑定到常量左值、非常量右值和常量右值。如果允许绑定到常量左值和常量右值,则非常量左值引用可以用于修改常量左值和常量右值,这明显违反了其常量的含义。如果允许绑定到非常量右值,则会导致非常危险的情况出现,因为非常量右值是一个临时对象,非常量左值引用可能会使用一个已经被销毁了的临时对象。

    常量左值引用可以绑定到所有类型的值,包括非常量左值、常量左值、非常量右值和常量右值。

    (1)非const左值引用只能绑定到非const左值;
    (2)const左值引用可绑定到const左值、非const左值、const右值、非const右值;
    (3)非const右值引用只能绑定到非const右值;
    (4)const右值引用可绑定到const右值和非const右值。

    大致意思是:模板参数的推导其实就是形参和实参的比较和匹配,如果形参是一个引用类型(如P&),那么就使用P来做类型推导;如果形参是一个cv-unqualified(没有const和volatile修饰的)右值引用类型(如P&&),并且实参是一个左值(如类型A的对象),就是用A&来做类型推导(使用A&代替A)。

    template <class _Tp> void f(_Tp &&amp ;) { /* do something */ }
    template <class _Tp> void g(const _Tp &&amp ;) { /* do something */ }
    int x = 123;
    f(x);   // ok,f()模板函数形参为非const非volatile右值引用类型,实参x为int类型左值,使用int&来做参数推导,因此调用f<int &>(int &amp ;)
    f(456); // ok,实参为右值,调用f<int>(int &&amp ;)
    g(x);   // error,g()函数模板参数为const右值引用类型,会调用g<int>(const int &&amp ;),通过右值引用规则四可知道,const右值引用不能绑定到左值,因此会导致编译错误

  • 相关阅读:
    local 不能解析为127.0.0.1
    完全使用接口方式调用WCF 服务
    【人生】自己对于求职应聘的一些感受
    OO的经典例子
    剪刀、石头、布机器人比赛
    TextTree 文本资料收集轻量级工具
    两个代替重复输入的小工具
    桌面助手 Desktop Helper 自动帮你关闭指定的窗口
    磁盘可用空间平衡
    用C#制造可以继承的“枚举”
  • 原文地址:https://www.cnblogs.com/yi-mu-xi/p/9983145.html
Copyright © 2011-2022 走看看