中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

C++右值引用的示例分析

發布時間:2021-06-07 14:44:09 來源:億速云 閱讀:187 作者:小新 欄目:開發技術

這篇文章主要介紹了C++右值引用的示例分析,具有一定借鑒價值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。

概述

在C++中,常量、變量或表達式一定是左值(lvalue)或右值(rvalue)。

左值:非臨時的(具名的,可在多條語句中使用,可以被取地址)。可以出現在等號的左邊或右邊。可分為非常量左值和常量左值。

C++右值引用的示例分析

右值:臨時的(不具名的,只在當前語句中有效,不能取地址)。只能出現在等號的右邊。可分為非常量右值和常量右值。

C++右值引用的示例分析

左值引用:對左值的引用就是左值引用。可分為非常量左值引用和常量左值引用。

C++右值引用的示例分析

注:常量左值引用是“萬能”的引用類型,可以綁定到所有類型的值,包括非常量左值、常量左值、非常量右值和常量右值。

右值引用(Rvalue References):對右值的引用就是右值引用。可分為非常量右值引用和常量右值引用。

C++右值引用的示例分析

為臨時對象的右值,它的生命周期很短暫,一般在執行完當前這條表達式之后,就釋放了。

通過將其賦值給右值引用,可以在不進行昂貴的拷貝操作的情況下被“續命”,讓其生命周期與右值引用類型變量的生命周期一樣長。

右值引用的兩個基本特性:移動語義(Move Semantics)和完美轉發(Perfect Forwarding)

移動語義(Move Semantics)

可將資源從一個對象轉移到另一個對象;主要解決減少不必要的臨時對象的創建、拷貝與銷毀。

移動構造函數MyClass(Type&& a):當構造函數參數是一個右值時,優先使用移動構造函數而不是拷貝構造函數MyClass(const Type& a)。

移動賦值運算符Type& operator = (Type&& a):當賦值的是一個右值時,優先使用移動賦值而不是拷貝賦值運算符Type& operator = (const Type& a)。

#include <iostream>
#include <string>
#include <utility>

struct MyClass
{
    std::string s;
    MyClass(const char* sz) : s(sz) 
    {
        std::cout << "MyClass sz:" << sz << std::endl;
    }
    MyClass(const MyClass& o) : s(o.s) 
    { 
        std::cout << "copy construct!\n"; 
    }

    MyClass(MyClass&& o) noexcept : s(std::move(o.s)) 
    {
        std::cout << "move construct!\n";
    }

    MyClass& operator=(const MyClass& other) { // copy assign
        std::cout << "copy assign!\n";
        s = other.s;
        return *this;
    }
    MyClass& operator=(MyClass&& other) noexcept { // move assign
        std::cout << "move assign!\n";
        s = std::move(other.s);
        return *this;
    }

    static MyClass GetMyClassGo(const char* sz)
    {
        MyClass o(sz); // 注意:可能會被NRVO優化掉
        return o;
    }
};

void func0(MyClass o)
{
    std::cout << o.s.c_str() << std::endl;
}

void func1(MyClass& o)
{
    std::cout << o.s.c_str() << std::endl;
}

void func2(const MyClass& o)
{
    std::cout << o.s.c_str() << std::endl;
}

void func3(MyClass&& o)
{
    std::cout << o.s.c_str() << std::endl;
}

int main(int arg, char* argv[])
{
    MyClass a1("how");
    MyClass a2("are");

    a2 = a1; // copy assign  注:a1是一個左值

    a2 = MyClass("you"); // move assign  注:MyClass("you")是一個右值

    MyClass a3(a1); // copy construct  注:a1是一個左值
    MyClass&& a4 = MyClass::GetMyClassGo("go"); // move construct  注:發生在MyClass::GetMyClassGo()內部
    MyClass a5 = MyClass::GetMyClassGo("china"); // move construct兩次  注:一次發生在MyClass::GetMyClassGo()內部;另一次發生在將返回值賦值給a5
    
    MyClass a6("let");
    MyClass a7("it");
    MyClass a8("go");
    MyClass a9("!");

    func0(a6);  // copy construct
    func1(a7);
    func2(a8);
    //func3(a9); // 編譯error: 不能把一個左值賦值給右值

    func0(MyClass::GetMyClassGo("god")); // move construct兩次  注:一次發生在MyClass::GetMyClassGo()內部;另一次發生在將返回值賦值給foo0參數時
    //func1(MyClass::GetMyClassGo("is")); // 編譯error: 不能把一個右值賦值給左值
    func2(MyClass::GetMyClassGo("girl")); // move construct  注:發生在MyClass::GetMyClassGo()內部
    func3(MyClass::GetMyClassGo("!"));  // move construct  注:發生在MyClass::GetMyClassGo()內部

    return 0;
}

注:測試以上代碼一定要關閉C++編譯器優化技術 -- RVO、NRVO和復制省略

使用std::move來實現移動語義

將一個左值或右值強制轉化為右值引用。 注:UE4中對應為MoveTemp模板函數

std::move(en chs)并不會移動任何東西,只是將對象的狀態或者所有權從一個對象轉移到另一個對象。注:只是轉移,沒有內存的搬遷或者內存拷貝。

① 基本類型(如:int、double等)被std::move移動后,其數值不會發生變化

② 復合類型被std::move移動后,處于一個未定義,但有效的狀態(大部分成員函數仍有意義)例如:標準庫中的容器類對象被移動后,會變成空容器

完美轉發(Perfect Forwarding)

針對模板函數,使用全能引用將一組參數原封不動的傳遞給另一個函數。

原封不動指:左值、右值、是否為const均不變。帶來如下3方面好處:

① 保證左值、右值的屬性

② 避免不必要的拷貝操作

③避免模版函數需要為左值、右值、是否為const的參數來實現不同的重載

全能引用(universal references、轉發引用)是一種特殊的模板引用類型,采用右值引用的語法形式(但它并不是右值引用)。如:template <class T> void func(T&& t) {}

T&& t在發生自動類型推斷的時候,它是未定的引用類型(universal references),T取決于傳入的參數t是右值還是左值。右值經過T&&變為右值引用,而左值經過T&&變為左值引用。

std::move就是使用全能引用實現的。其定義如下:

template <typename T>
typename remove_reference<T>::type&& move(T&& t)
{
    return static_cast<typename remove_reference<T>::type &&>(t);
}


/*****************************************
std::remove_reference功能為去除類型中的引用

std::remove_reference<T &>::type ---> T
std::remove_reference<T &&>::type ---> T
std::remove_reference<T>::type ---> T
******************************************/
//原始的,最通用的版本
template <typename T> struct remove_reference{
    typedef T type;  //定義T的類型別名為type
};
 
//部分版本特例化,將用于左值引用和右值引用
template <class T> struct remove_reference<T&> //左值引用
{ typedef T type; }
 
template <class T> struct remove_reference<T&&> //右值引用
{ typedef T type; }

① 當t為左值時,展開為:U&& move(U& t)  注:右值引用類型變量也是左值

② 當t為右值時,展開為:U&& move(U&& t)

最后,通過static_cast<>進行強制類型轉換返回右值引用。注:static_cast之所以能使用類型轉換,是通過remove_refrence::type模板移除T&&,T&的引用,獲取具體類型T(模板偏特化)。

引用折疊

規律:含左值引用就是左值引用,否則就是右值引用

C++右值引用的示例分析

使用std::forward實現參數的完美轉發。其定義如下(en chs):

template <typename T>
T&& forward(remove_reference_t<T>& arg) // forward an lvalue as either an lvalue or an rvalue
{ 
    return static_cast<T&&>(arg);
}

template <typename T>
T&& forward(remove_reference_t<T>&& arg) // forward an rvalue as an rvalue
{ 
    static_assert(!is_lvalue_reference_v<T>, "bad forward call");
    return static_cast<T&&>(arg);
}

最后,通過static_cast<>進行引用折疊,并強制類型轉換后,實現原封不動轉發參數。 注:UE4中對應為Forward模板函數

void bar(int& a, int&& b)
{
    int c = a + b;
}

void func(int a, int&& b)
{
    int c = a + b;
}

template <typename A, typename B>
void foo(A&& a, B&& b) { // a, b為左值引用或右值引用
    bar(std::forward<A>(a), std::forward<B>(b)); // 在std::forward轉發前后,參數a,b的類型完全不變
}

int main(int arg, char* argv[])
{
    int a = 10;

    foo(a, 20); // 展開為void foo(int& a, int&& b),經過std::forward完美轉發后,會調用到void bar(int& a, int&& b)函數

    func(std::forward<int>(a), std::forward<int&&>(30)); // 經過std::forward完美轉發后,會調用到void func(int a, int&& b)函數

    return 0;
}

感謝你能夠認真閱讀完這篇文章,希望小編分享的“C++右值引用的示例分析”這篇文章對大家有幫助,同時也希望大家多多支持億速云,關注億速云行業資訊頻道,更多相關知識等著你來學習!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

c++
AI

黄浦区| 武胜县| 奉化市| 堆龙德庆县| 兖州市| 花莲县| 房山区| 昌吉市| 宜章县| 上栗县| 开原市| 仲巴县| 富源县| 常熟市| 乡城县| 衡水市| 夹江县| 建德市| 会昌县| 桃园县| 中超| 象山县| 内黄县| 申扎县| 长沙市| 祁连县| 临夏市| 克什克腾旗| 沛县| 唐海县| 芷江| 潞城市| 宁陕县| 昭通市| 华阴市| 从化市| 新巴尔虎右旗| 遵化市| 凯里市| 南和县| 谷城县|