日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

C++ std::move()和完美转发

發布時間:2023/12/20 c/c++ 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C++ std::move()和完美转发 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

std::move()、std::forward<T>、模板類型推斷分析

?

引用折疊原則和完美轉發是有聯系的,可以說后者是基于前者的某些特性實現的,具體來看一下。

要理解完美轉發,需要了解兩個知識點:

  • 引用折疊原則(Reference collapsing rules)。

  • 右值函數模版參數類型推導(Template argument deduction)

  • 我們先來分析一下為什么需要使用到move呢?

    C++11多出來一個move語義,意圖是解決臨時對象重復拷貝和釋放引發的資源浪費,move與右值引用進行搭配可以完美的解決這個問題。
    比如在進行vector中的insert函數的時候,如果模板類型是string,通過move(str1)我們就可以只將string中的指針進行交換,即可實現插入到vector容器中的操作。而不用再進行深拷貝的動作。
    需要注意的是,如果使用move進行左值變右值之后,該左值不能再利用,因為它里面的信息可能已經被更改,對應的string就是,指向字符串的指針被打斷了。

    下面這張圖是模板類型推斷原則:

    ?
    這是函數模板參數類型推導中一種比較特殊的情況,這種情況會把模板參數作為右值引用使用,例如:

    template<typename T> void foo(T&&);
    • ?

    其中T為模板類型,T&&為參數類型。這種情況會產生兩種結果:

    1. 當傳給foo函數的參數是一個左值引用時,例如:

    int i = 29; foo(i);//i為左值引用
    • ?

    此時,T的類型為int的左值引用:int&,參數類型為int & &&,(既T&&),結合上面的引用折疊規則,最終參數的類型為int的左值引用:int&。
    2. 當傳給foo函數的參數是一個右值引用時,例如:

    foo(29);
    • ?

    此時,T的類型為int,參數類型為int&&,(既T&&)。

    那么,為什么需要forward呢?
    我們先來看下以下例子:

    template<typename T> void show1(T && a) {cout << "我是右值引用" << endl; }template<typename T> void show1(T & a) {cout << "我是左值引用" << endl; }template<typename T> void show(T && a) {show1(forward<T>(a)); } //我們通過以下進行調用; show(2);
    • ?

    該函數第進入show之后會調用show1的調用,如果此時沒有用forward進行轉發的話,會調用到
    左值引用版本,而不會調用到右值引用的版本。所有forward就是進行完美轉發的作用,當傳入的是左值引用
    的時候,會調用到左值引用的版本,當調用到右值引用的時候,函數里面也會調用到右值引用的版本 那么他是怎么實現的呢?
    通過以上代碼的分析,我們可以發現,forward會進行類型的轉發。具體實現原理就是上面所說的引用折疊原則。

    下面是VS2015下的實現源碼。

    // TEMPLATE FUNCTION forward template<class _Ty> inlineconstexpr _Ty&& forward(typename remove_reference<_Ty>::type& _Arg) _NOEXCEPT{ // forward an lvalue as either an lvalue or an rvaluereturn (static_cast<_Ty&&>(_Arg));}template<class _Ty> inlineconstexpr _Ty&& forward(typename remove_reference<_Ty>::type&& _Arg) _NOEXCEPT{ // forward an rvalue as an rvaluestatic_assert(!is_lvalue_reference<_Ty>::value, "bad forward call");return (static_cast<_Ty&&>(_Arg));}

    我們就上面那個例子來進行分析:
    1、傳入的是左值的時候。

    void show(int& && a) {//此時T為 int&類型。a通過引用折疊原則為int&類型show1(forward<int&>(a)); }

    此時forward會調用下面這個版本的函數。

    constexpr int& && forward(typename remove_reference<int&>::type& _Arg) _NOEXCEPT{ // forward an lvalue as either an lvalue or an rvaluereturn (static_cast<int& &&>(_Arg));}

    那么,此時返回的就是int& &&類型,通過引用折疊原則即為 int &,完成了左值的轉發

    2、傳入的是右值的時候。

    下面是類型推斷調用的時候生成的函數。

    void show(int && a) {//此時T為 int類型。a為 int&& 類型show1(forward<int>(a)); }
    • ?

    相應地就會調用到下面這個forward版本:

    constexpr int && forward(typename remove_reference<int>::type&& _Arg) _NOEXCEPT { // forward an rvalue as an rvalue static_assert(!is_lvalue_reference<int>::value, "bad forward call"); return (static_cast<int &&>(_Arg)); }

    我們可以看出上面的這個forward會返回右值引用,則實現了右值引用的完美轉發。

    總結

    1、move函數是將一個左值轉為右值引用,轉換之后,改左值就不能再進行使用了。
    2、forward函數是進行類型的轉發,可以將左值引用繼續轉發為左值,右值引用繼續轉發為右值引用。

    總結

    以上是生活随笔為你收集整理的C++ std::move()和完美转发的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。