美文网首页
C++11左值右值、左值引用、右值引用、万能引用、完美转发

C++11左值右值、左值引用、右值引用、万能引用、完美转发

作者: jdzhangxin | 来源:发表于2021-07-19 11:16 被阅读0次

    1. 左值&右值

        int n = 10;
        int m = n;
        // 10 = n; // 字面量右值
        const char* s = "123abc";
        // "abcd" = s; // 字面量右值
        m = n + 2;
        // n + 2 = m; // 中间结果右值
        string str = string(s);
        // string(s) = str; // 匿名对象右值
    
    • 右值:只能在=右边使用的值(字面量、中间结果、临时对象/匿名对象),无法直接取地址,不能使用左值引用。
    • 左值:可以在=左边使用的值

    2. 左值引用&右值引用

    #include <iostream>
     
    using namespace std;
     
    void Print(int n){ cout << n << endl; }
    void Print2(int& n){ cout << n << endl; }
    void Print3(const int& n){ cout << n << endl; }
    // 右值引用
    void Print4(int&& n){ cout << n << endl; }
    int main() {
        // int& f = 10; // 字面量不能初始化左值引用
    
        int m = n;     
        Print(m); // int n = m;
        Print(10);// int n = 10;
    
        Print2(m); // int& n = m;
        // Print2(10);// int& n = 10; // 右值不能初始化左值引用
        
        Print3(m); // const int& n = m;
        Print3(10);// const int& n = 10; // const左值引用可以初始化左值和右值
     
        // Print4(m); // int&& n = m; // 左值不能初始化右值引用
        Print4(10);// int&& n = 10;
    }
    
    1. 左值引用只能用左值初始化
    2. 右值引用只能用右值初始化
    3. const左值引用可以初始化左值和右值。

    右值引用是左值还是右值?

    3. 移动构造函数&移动赋值运算符重载

    3.1 不可复制对象的移动

    #include <iostream>
     
    using namespace std;
    // 不可复制对象的移动
    class Uncopy{
    public:
        Uncopy() = default;
        ~Uncopy() = default;
        Uncopy(const Uncopy&) = delete;
        Uncopy& operator=(const Uncopy&) = delete;
        Uncopy(Uncopy&&){ cout << "rvalue copy constructor" << endl;}
        Uncopy& operator=(Uncopy&&) {cout << "rvalue assign " << endl; return *this;}
    };
     
    void Param(Uncopy w){}
     
    Uncopy Return(){
        Uncopy v;
        return move(v);
        // return Uncopy(); // 匿名对象
    }
    int main(){
        Uncopy u;
        // Uncopy w = u; // 拷贝构造
        Uncopy w = Uncopy(); // 移动构造
        Uncopy w2 = move(u); // 移动构造
        Uncopy v;
        // v = u; // 赋值运算符重载
        v = Uncopy(); // 移动运算符重载
        v = move(u); // 移动运算符重载
     
        // Param(u); // Uncopy w =u;
        Param(Uncopy()); // Uncopy w =u;
        Param(move(u)); // Uncopy w =u;
        Return(); 
    }
    

    不可复制对象,可以使用移动语法做拷贝构造和赋值。
    移动的条件:

    1. 只有右值才能移动,如果左值要移动需要转换成右值(move())。
    2. 对象的类要实现移动构造函数和移动赋值运算符重载。

    3.2 可复制对象的移动

    #include <iostream>
    #include <vector>
     
    using namespace std;
    // 可复制对象使用移动
    class Simple{
    public:
        Simple(){cout<< "constructor" << endl;}
        Simple(const Simple&){cout<< "copy constructor" << endl;}
        Simple& operator=(const Simple&){cout<< "assign override" << endl; return *this;}
        Simple(Simple&&){cout<< "move constructor" << endl;}
        Simple& operator=(Simple&&){cout<< "move override" << endl; return *this;}
    };
     
    int main(){
        Simple simple;
        Simple simple2 = move(simple);
        simple2 = move(simple); 
    }
    

    移动的条件:

    1. 只有右值才能移动,如果左值要移动需要转换成右值(move())。
    2. 对象的类实现了移动构造函数和移动赋值运算符重载 。否则,执行拷贝操作。

    3.3 STL中的移动

    #include <iostream>
    #include <vector>
     
    using namespace std;
    // 可复制对象使用移动
    class Simple{
    public:
        Simple(){cout<< "constructor" << endl;}
        Simple(const Simple&){cout<< "copy constructor" << endl;}
        Simple& operator=(const Simple&){cout<< "assign override" << endl; return *this;}
        Simple(Simple&&){cout<< "move constructor" << endl;}
        Simple& operator=(Simple&&){cout<< "move override" << endl; return *this;}
    };
     
     
    int main(){
        string s = "abcd";
        // string t = s;
        string t = move(s);
        cout << (void*)s.c_str() << " " << s << endl;
        cout << (void*)t.c_str() << " " << t << endl;
     
        vector<int> vec1 = {1,2,3,4,5};
        vector<int> vec2;
        vec2 = move(vec1);
        cout << vec1.size() << "," << vec2.size() << endl;
     
        vector<Simple> vs;
        //vs.push_back(simple); // 拷贝构造
        //vs.push_back(simple); // 拷贝构造
        //vs.push_back(simple); // 拷贝构造
        //vs.push_back(simple); // 拷贝构造
        vs.emplace_back(move(simple)); // 移动构造
        vs.emplace_back(move(simple)); // 移动构造
        vs.emplace_back(move(simple)); // 移动构造
    }
    
    • C++11 string和容器都实现移动构造函数和移动赋值运算符重载。
    • C++11 STL容器提供了移动操作的成员函数emplace_*()

    4. 万能引用&完美转发

    #include <iostream>
    #include <vector>
     
    using namespace std;
    // 可复制对象使用移动
    class Simple{
    public:
        Simple(){cout<< "constructor" << endl;}
        Simple(const Simple&){cout<< "copy constructor" << endl;}
        Simple& operator=(const Simple&){cout<< "assign override" << endl; return *this;}
        Simple(Simple&&){cout<< "move constructor" << endl;}
        Simple& operator=(Simple&&){cout<< "move override" << endl; return *this;}
     
        void Test()&{ // 相当于void Test(Simple*& this)
           cout << "lvalue Test" << endl;
        }
        void Test()&&{ // 相当于void Test(Simple*&& this)
           cout << "rvalue Test" << endl;
        }
    };
     
     
    // void Func(Simple s){}
    void Func(Simple& s){
       cout << "lvalue" << endl;
    }
    void Func(Simple&& s){
       cout << "rvalue" << endl;
    }
    // void Func(const Simple& s){}
      
    template<typename T>
    void TemplateFunc(T&& param){// 模板参数&&:通用引用/万能引用,根据参数左右值类型的不同,生成不同参数类型的函数。
        // Func(param);
        // 完美转发
        Func(forward<T>(param));
        forward<T>(param).Test();
    }
     
    int main(){
        Simple s;
        Func(s);
        Func(move(s));
     
        s.Test();
        Simple().Test();
     
        TemplateFunc(s);// 传入左值 T&& => T&  void TemplateFunc(Simple& param)
        TemplateFunc(Simple()); // 传入右值 T&& => T&& void TemplateFunc(Simple&& param)
    }
    
    1. 函数参数中的&&表示右值引用,函数模板参数中的&&表示万能引用。通用引用/万能引用,根据参数左右值类型的不同,生成不同参数类型的函数。
    2. forward<T>()完美转发根据万能引用参数的不同(左值引用还是右值引用),恢复参数的状态(左值引用保持左值,右值引用转成右值),实现函数调用的转发(传入左值,调用左值引用的函数;传入右值,调用右值引用的函数)。

    相关文章

      网友评论

          本文标题:C++11左值右值、左值引用、右值引用、万能引用、完美转发

          本文链接:https://www.haomeiwen.com/subject/palzpltx.html