• C++11常用新特性——右值引用&&


    右值引用&&

    左值与右值

    在C++的世界里,值被分类为左值和右值。简单地说,左值是那些在表达式之后仍然存在的对象,如变量。而右值是在表达式结束后不再存在的临时对象,如一些临时产生的值或对象。

    我们可以通过一个简单的方法来鉴别它们:**如果你能够取得一个表达式的地址,那么它是左值;否则,它是右值。**例如,具有名字的对象总是左值,而字面量和一些表达式结果是右值。

    为了更深入地理解右值,C++11将其进一步细分为纯右值将亡值。纯右值包括临时变量、某些运算表达式的结果和大部分字面量。将亡值则是与右值引用有关的表达式,它们常常涉及到移动操作。

    不过,要记住的是,这两者的细微差别通常不会影响到大部分的应用。在实际编程中,我们经常将它们统一看作右值。

    例如下面示例:

    class Object {
        // some members...
    };
    
    Object createObject() {
        return Object();
    }
    
    int main() {
        Object obj;             // 'obj' 是一个左值
        Object&& tempObj = createObject(); // 'createObject()' 返回一个右值
    
        int a = 42;             // 'a' 是一个左值
        int&& rvalueRef = a + 5;   // 'a + 5' 是一个右值
    
        // 取地址示例
        Object* pObj = &obj;       // 可以,因为 'obj' 是左值
        // Object* pTempObj = &createObject();  // 错误,因为 'createObject()' 是一个右值
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    左值引用与右值引用

    传统的C++引用(C++98)现在被称为左值引用,它允许我们为变量创建一个别名。而C++11引入了右值引用的概念,使我们能够为右值也创建一个别名。

    右值引用的引入极大地丰富了C++的语义,特别是在涉及到移动语义时。通过使用右值引用,我们可以有效地"转移"资源,而不是复制,从而提高效率。

    当我们给右值引用命名后,它其实变成了一个左值。

    #include 
    #include  // for move
    
    using namespace std;
    
    class Data {
    public:
        Data() { cout << "Constructor called!" << endl; }
    
        Data(const Data &) { cout << "Copy constructor called!" << endl; }
    
        Data(Data &&) { cout << "Move constructor called!" << endl; }
    };
    
    Data createData() {
        return Data();
    }
    
    int main() {
        // 左值引用示例
        int x = 10;
        int &lvalueRef = x; // 左值引用
        lvalueRef += 5;
        cout << "x: " << x << endl; // x现在是15
    
        // 右值引用示例
        Data &&rvalueRef = createData(); // 调用构造函数但不调用拷贝构造函数
    
        Data dataObj;
        Data copiedDataObj = dataObj; // 调用拷贝构造函数
        Data movedDataObj = move(dataObj); // 调用移动构造函数
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    当一个临时对象(右值)被绑定到一个右值引用时,它的生命周期会延长,与该右值引用的生命周期相同。

    通常情况下,临时对象在表达式结束后就被销毁。但是,当它被绑定到右值引用时,这种销毁被延迟,直到该引用的生命周期结束。

    引入右值引用的主要目的是实现移动语义。

    左值引用只能绑定(关联、指向)左值,右值引用只能绑定右值,如果绑定的不对,编译就会失败。

    但是,常量左值引用却是个奇葩,它可以算是一个万能的引用类型,它可以绑定非常量左值、常量左值、右值,而且在绑定右值的时候,常量左值引用还可以像右值引用一样将右值的生命期延长,缺点是,只能读不能改。

    int a = 1;        
    const int& ra = a;   // a是非常量左值。
    
    const int b = 1;  
    const int& rb = b;  // b是常量左值。
    
    const int& rc = 1;   // 1是右值。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 总结

    总结一下,其中T是一个具体类型:

    1. 左值引用, 使用 T&, 只能绑定左值。
    2. 右值引用, 使用 T&&, 只能绑定右值。
    3. 已命名的右值引用是左值。
    4. 常量左值,使用 const T&, 既可以绑定左值又可以绑定右值。
  • 相关阅读:
    数据结构:链表(1)
    通俗易懂的MVCC
    11.QA模型选择,欠拟合和过拟合
    力扣100097. 合法分组的最少组数(哈希+贪心)
    Java数据结构—优先级队列(堆)
    【Python刷题篇】——Python入门 09 字典(下)
    50行Python代码白嫖Github Actions, 每天检测收录优质项目的存活状态(提供csv纯净数据下载)
    Win10常用快捷键
    java计算机毕业设计高校学生智慧党建系统设计与开发MyBatis+系统+LW文档+源码+调试部署-++
    nacos命名空间的配置
  • 原文地址:https://blog.csdn.net/m0_73790534/article/details/133933136