最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C++ 右值語義相關(guān)總結(jié)

 更新時間:2021年02月26日 16:18:38   作者:后端技術(shù)小屋  
這篇文章主要介紹了C++ 右值語義的的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)使用c++,感興趣的朋友可以了解下

在現(xiàn)代C++的眾多特性中,右值語義(std::move和std::forward)大概是最神奇也最難懂的特性之一了。本文簡要介紹了現(xiàn)代C++中右值語義特性的原理和使用。

1 什么是左值,什么是右值?

int a = 0;  // a是左值,0是右值
int b = rand(); // b是左值,rand()是右值

直觀理解:左值在等號左邊,右值在等號右邊

深入理解:左值有名稱,可根據(jù)左值獲取其內(nèi)存地址,而右值沒有名稱,不能根據(jù)右值獲取地址。

2 引用疊加規(guī)則

左值引用A&和右值引用A&&可相互疊加, 疊加規(guī)則如下:

A& + A& = A&
A& + A&& = A&
A&& + A& = A&
A&& + A&& = A&&

舉例說明,在模板函數(shù)void foo(T&& x)中:

如果T是int&類型, T&&為int&,x為左值語義
如果T是int&&類型, T&&為int&&, x為右值語義
也就是說,不管輸入?yún)?shù)x為左值還是右值,都能傳入函數(shù)foo。區(qū)別在于兩種情況下,編譯器推導(dǎo)出模板參數(shù)T的類型不一樣。

3 std::move

3.1 What?

在C++11中引入了std::move函數(shù),用于實現(xiàn)移動語義。它用于將臨時變量(也有可能是左值)的內(nèi)容直接移動給被賦值的左值對象。

3.2 Why?

知道了std::move是干什么的,他能給我們的搬磚工作帶來哪些好處呢? 舉例說明:

如果類X包含一個指向某資源的指針,在左值語義下,類X的復(fù)制構(gòu)造函數(shù)定義如下:

X::X() 
{
 // 申請資源(指針表示)
}

X::X(const X& other)
{
 // ...
 // 銷毀資源 
 // 克隆other中的資源
 // ...
}

X::~X() 
{
 // 銷毀資源
}

假設(shè)應(yīng)用代碼如下。其中,對象tmp被賦給a之后,便不再使用。

X tmp;
// ...經(jīng)過一系列初始化...
X a = tmp;

在上面的代碼中,執(zhí)行步驟:

  • 先執(zhí)行一次默認(rèn)構(gòu)造函數(shù)(默認(rèn)構(gòu)造tmp對象)
  • 再執(zhí)行一次復(fù)制構(gòu)造函數(shù)(復(fù)制構(gòu)造a對象)
  • 退出作用域時執(zhí)行析構(gòu)函數(shù)(析構(gòu)tmp和a對象)

從資源的視角來看,上述代碼中共執(zhí)行了2次資源申請和3次資源釋放。

那么問題來了,既然對象tmp只是一個臨時對象,在執(zhí)行X a = tmp;時,對象a能否將tmp的資源'偷'過來,直接為我所用,而不影響原來的功能? 答案是可以。

X::X(const X& other)
{
 // 使用std::swap交換this和other的資源  
}

通過'偷'對象tmp的資源,減少了資源申請和釋放的開銷。而std::swap交換指針代價極小,可忽略不計。

3.3 How?

到現(xiàn)在為止,我們明白了std::move將要達(dá)到的效果,那么它究竟是怎么實現(xiàn)的呢?

template<class T> 
typename remove_reference<T>::type&&
std::move(T&& a) noexcept
{
 typedef typename remove_reference<T>::type&& RvalRef;
 return static_cast<RvalRef>(a);
}

不管輸入?yún)?shù)為左值還是右值,都被remove_reference去掉其引用屬性,RvalRef為右值類型,最終返回類型為右值引用。

3.4 Example

在實際使用中,一般將臨時變量作為std::move的輸入?yún)?shù),并將返回值傳入接受右值類型的函數(shù)中,方便其'偷取'臨時變量中的資源。需要注意的是,臨時變量被'偷'了之后,便不能對其進(jìn)行讀寫,否則會產(chǎn)生未定義行為。

#include <utility>    
#include <iostream>   
#include <string>    
#include <vector>    
        
void foo(const std::string& n) 
{        
 std::cout << "lvalue" << std::endl;
}        
        
void foo(std::string&& n)  
{        
 std::cout << "rvalue" << std::endl;
}        
        
void bar()      
{        
 foo("hello");    // rvalue
 std::string a = "world";  
 foo(a);      // lvalue
 foo(std::move(a));   // rvalue
}

int main()
{
 std::vector<std::string> a = {"hello", "world"};
 std::vector<std::string> b;

 b.push_back("hello");   // 開銷:string復(fù)制構(gòu)造
 b.push_back(std::move(a[1])); // 開銷:string移動構(gòu)造(將臨時變量a[1]中的指針偷過來)

 std::cout << "bsize: " << b.size() << std::endl;
 for (std::string& x: b)
 std::cout << x << std::endl;
 bar();
 return 0;
}

4 std::forward

4.1 What?

std::forward用于實現(xiàn)完美轉(zhuǎn)發(fā)。那么什么是完美轉(zhuǎn)發(fā)呢?完美轉(zhuǎn)發(fā)實現(xiàn)了參數(shù)在傳遞過程中保持其值屬性的功能,即若是左值,則傳遞之后仍然是左值,若是右值,則傳遞之后仍然是右值。

簡單來說,std::move用于將左值或右值對象強(qiáng)轉(zhuǎn)成右值語義,而std::forward用于保持左值對象的左值語義和右值對象的右值語義。

4.2 Why?

#include <utility>
#include <iostream>

void bar(const int& x)
{
 std::cout << "lvalue" << std::endl;
}

void bar(int&& x)
{
 std::cout << "rvalue" << std::endl;
}

template <typename T>
void foo(T&& x)
{
 bar(x);
}

int main()
{
 int x = 10; 
 foo(x); // 輸出:lvalue
 foo(10); // 輸出:lvalue
 return 0;
}

執(zhí)行以上代碼會發(fā)現(xiàn),foo(x)和foo(10)都會輸出lvalue。foo(x)輸出lvalue可以理解,因為x是左值嘛,但是10是右值,為啥foo(10)也輸出lvalue呢?

這是因為10只是作為函數(shù)foo的右值參數(shù),但是在foo內(nèi)部,10被帶入了形參x,而x是一個有名字的變量,即右值,因此foo中bar(x)還是輸出lvalue。

那么問題來了,如果我們想在foo函數(shù)內(nèi)部保持x的右值語義,該怎么做呢?std::forward便派上了用場。

只需改寫foo函數(shù):

template <typename T>
void foo(T&& x)
{
 bar(std::forward<T>(x));
}

4.3 How?

std::forward聽起來有點神奇,那么它到底是如何實現(xiàn)的呢?

template<typename T, typename Arg> 
shared_ptr<T> factory(Arg&& arg)
{ 
 return shared_ptr<T>(new T(std::forward<Arg>(arg)));
}
template<class S>
S&& forward(typename remove_reference<S>::type& a) noexcept
{
 return static_cast<S&&>(a);
}

X x;
factory<A>(x);

如果factory的輸入?yún)?shù)是一個左值,那么Arg = X&,根據(jù)疊加規(guī)則,std::forward<Arg> = X&。因此,在這種情況下,std::forward<Arg>(arg)仍然是左值。

相反,如果factory輸入?yún)?shù)是一個右值,那么Arg = X,std::forward<Arg> = X。這種情況下,std::forward<Arg>(arg)是一個右值。

恰好達(dá)到了保留左值or右值語義的效果!

4.4 Example

直接上代碼。如果前面都懂了,相信這段代碼的輸出結(jié)果也能猜個八九不離十了。

#include <utility>
#include <iostream>

void overloaded(const int& x)
{
 std::cout << "[lvalue]" << std::endl;
}

void overloaded(int&& x)
{
 std::cout << "[rvalue]" << std::endl;
}

template <class T> void fn(T&& x)
{
 overloaded(x);
 overloaded(std::forward<T>(x));
}

int main()
{
 int i = 10; 
 overloaded(std::forward<int>(i));
 overloaded(std::forward<int&>(i));
 overloaded(std::forward<int&&>(i));
 
 fn(i);
 fn(std::move(i));

 return 0;
}

以上就是C++ 右值語義相關(guān)總結(jié)的詳細(xì)內(nèi)容,更多關(guān)于C++ 右值語義的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • C語言版實現(xiàn)鏈隊列

    C語言版實現(xiàn)鏈隊列

    這篇文章主要為大家詳細(xì)介紹了C語言版實現(xiàn)鏈隊列,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-07-07
  • Vscode自定義注釋模板的實現(xiàn)示例

    Vscode自定義注釋模板的實現(xiàn)示例

    本文主要介紹了Vscode自定義注釋模板的實現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-07-07
  • C語言解決字符串中插入和刪除某段字符串問題

    C語言解決字符串中插入和刪除某段字符串問題

    這篇文章主要介紹了C語言解決字符串中插入和刪除某段字符串問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-02-02
  • C生萬物C語言宏將整數(shù)二進(jìn)制位的奇偶數(shù)位交換

    C生萬物C語言宏將整數(shù)二進(jìn)制位的奇偶數(shù)位交換

    這篇文章主要為大家介紹了C生萬物C語言使用宏將整數(shù)二進(jìn)制位的奇偶數(shù)位交換示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-02-02
  • OpenGL通過中點法繪制直線和圓

    OpenGL通過中點法繪制直線和圓

    這篇文章主要為大家詳細(xì)介紹了OpenGL通過中點法繪制直線和圓,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-02-02
  • 基于malloc與free函數(shù)的實現(xiàn)代碼及分析

    基于malloc與free函數(shù)的實現(xiàn)代碼及分析

    本篇文章介紹了malloc與free函數(shù)的實現(xiàn)代碼及分析。需要的朋友參考下
    2013-05-05
  • C語言實現(xiàn)學(xué)生成績管理系統(tǒng)課程設(shè)計

    C語言實現(xiàn)學(xué)生成績管理系統(tǒng)課程設(shè)計

    這篇文章主要為大家詳細(xì)介紹了C語言實現(xiàn)學(xué)生成績管理系統(tǒng)課程設(shè)計,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-07-07
  • Windows下Qt打包自動尋找依賴的DLL

    Windows下Qt打包自動尋找依賴的DLL

    本文介紹了兩種在Windows下使用Qt打包應(yīng)用程序并自動尋找依賴DLL的方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-12-12
  • C++關(guān)鍵字mutable學(xué)習(xí)筆記

    C++關(guān)鍵字mutable學(xué)習(xí)筆記

    這篇文章主要為大家介紹了C++關(guān)鍵字mutable學(xué)習(xí)筆記,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-10-10
  • 深入c語言continue和break的區(qū)別詳解

    深入c語言continue和break的區(qū)別詳解

    本篇文章是對c語言中continue和break的區(qū)別進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-05-05

最新評論

开封县| 宜春市| 龙胜| 翁源县| 安乡县| 栖霞市| 曲沃县| 牙克石市| 灵山县| 福安市| 江陵县| 长春市| 花莲市| 葵青区| 五大连池市| 丁青县| 察隅县| 广西| 榕江县| 南丰县| 马龙县| 株洲县| 诸城市| 巩留县| 镇沅| 阿拉尔市| 荃湾区| 积石山| 元朗区| 南宁市| 石渠县| 甘孜| 简阳市| 新邵县| 松桃| 苏州市| 游戏| 林西县| 峨眉山市| 达州市| 嵊州市|