C++中的ravalue学习笔记

一、学习笔记

1. A a = 42; 会先以42为参数构造一个A类对象,然后调用拷贝构造函数来构造a,目前编译器优化掉了拷贝构造函数的调用,测试拷贝构造函
数是没有被调用的,但是其权限不能为private的,即使提供了重载的拷贝构造函数(其它没有调用到的构造函数可以被设置为private的)

2. 打印出下面两个地址相同,编译器优化过了

B get() {
    B b1(1);
    cout << &b1 << endl; //地址1
    return b1;
}

int main() {
    B b = get();
    cout << &b << endl; //地址2
    return 0;
}

3. C++11标准引入了右值引用,使用它可以使临时对象的拷贝具有move语意,从而可以使临时对象的拷贝具有浅拷贝般的效率,这样便可以从
一定程度上解决临时对象的深度拷贝所带来的效率折损。

4. 区分一个表达式是左值还是右值,最简便的方法就是看能不能够对它取地址:如果能,就是左值;否则,就是右值。
由于右值引用的引入,C++11标准中对表达式的分类不再是“非左即右”那么简单,不过为了简单地理解,我们暂时只需区分左值右值即可,C++11标准中的分类后面会有描述。

5. 下面简单地总结了左值引用和右值引用的绑定规则(函数类型对象会有所例外):
(1)非const左值引用只能绑定到非const左值;
(2)const左值引用可绑定到const左值、非const左值、const右值、非const右值;
(3)非const右值引用只能绑定到非const右值;
(4)const右值引用可绑定到const右值和非const右值。

6. 右值引用绑定到字面值常量同样符合上述规则,例如:int &&rr = 123;,这里的字面值123虽然被称为常量,可它的类型为int,而不是const int。对此C++03标准文档4.4.1节及其脚注中有如下说明:

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

二、Demo

struct A {
    A(){} 
};

A rvalue() {return A();}              // 返回一个非const右值对象
const A const_rvalue() {return A();}  // 返回一个const右值对象

// void fun() {}
// typedef decltype(fun) FUN;  // typedef void FUN();

int main()
{

    A lvalue;                             // 非const左值对象
    const A const_lvalue;                 // const左值对象


    // 规则一:非const左值引用只能绑定到非const左值
    A &lvalue_reference1 = lvalue;         // ok
    A &lvalue_reference2 = const_lvalue;   // error
    A &lvalue_reference3 = rvalue();       // error
    A &lvalue_reference4 = const_rvalue(); // error

    // 规则二:const左值引用可绑定到const左值、非const左值、const右值、非const右值
    const A &const_lvalue_reference1 = lvalue;         // ok
    const A &const_lvalue_reference2 = const_lvalue;   // ok
    const A &const_lvalue_reference3 = rvalue();       // ok
    const A &const_lvalue_reference4 = const_rvalue(); // ok

    // 规则三:非const右值引用只能绑定到非const右值
    //A &&rvalue_reference1 = lvalue;         // error
    //A &&rvalue_reference2 = const_lvalue;   // error
    //A &&rvalue_reference3 = rvalue();       // ok
    //A &&rvalue_reference4 = const_rvalue(); // error

    // 规则四:const右值引用可绑定到const右值和非const右值,不能绑定到左值
    //const A &&const_rvalue_reference1 = lvalue;         // error
    //const A &&const_rvalue_reference2 = const_lvalue;   // error
    //const A &&const_rvalue_reference3 = rvalue();       // ok
    //const A &&const_rvalue_reference4 = const_rvalue(); // ok

    // 规则五:函数类型例外
    //FUN       &  lvalue_reference_to_fun       = fun; // ok
    //const FUN &  const_lvalue_reference_to_fun = fun; // ok
    //FUN       && rvalue_reference_to_fun       = fun; // ok
    //const FUN && const_rvalue_reference_to_fun = fun; // ok

    return 0;
}

参考:https://www.cnblogs.com/opangle/archive/2012/11/19/2777131.html

原文地址:https://www.cnblogs.com/hellokitty2/p/10632191.html