<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    so true

    心懷未來,開創未來!
    隨筆 - 160, 文章 - 0, 評論 - 40, 引用 - 0
    數據加載中……

    深度剖析右值、右值引用、完美轉發等相關概念

    右值、右值引用(T&&)、std::move、完美轉發(std::forward)、通用引用(universal reference)、引用折疊(reference collapsing)這些概念貌似很玄,但其實很它們想做的事情很簡單而且很單一,抓住本質就豁然開朗了。
    上面這些概念的引入完全是為了解決一個問題:盡可能用淺拷貝代替深拷貝;具體該如何實施呢:
    1. 定義move constructor或move operator=,如果你新定義的類沒有move constructor或move operator=,那根本就用不上上面那些高級的概念;
    2. 告訴編譯器什么時候用move constructor(而不是用copy constructor),這就需要借助std::move來把左值轉成右值;
    下面是一些零散的箴言:
    左值:能用&來取地址的東西(有名字的都是左值,不管其是否是const的,而且引用都是左值,因為引用肯定得起個名字去引用另外一個東西);
    右值:不能用&來取地址的東西(說白了就是沒名字的東西,例如函數的返回值);
    const T&是萬能引用,即 const T& t = XXX; //XXX是左值、右值都可以;
    T& t = XXX; //XXX必須是左值;
    T&& t = XXX; //XXX必須是右值;
    const T&& t = XXX; //XXX必須是右值;
    不要把T&&和const T&劃等號,兩個都能hold住臨時變量,給臨時變量續命,但:
    T&& t1 = get_val();
    const T& t2 = get_val();
    t1和t2都是左值,因為都可以用&來取地址,但t1是非const的,因此可以t1.xxx = yyy;去修改t1里的內容(當然如果你定義const T&& t1 = get_val(),那就不能更改了),這樣一來,下面這種代碼受益了:
        string name = get_name(); //因為后面要修改name,所以不能用const string& name
        trim(name);
        可以修改為:
        string&& name = get_name();
        trim(name);
        
    關于右值引用的生命周期(續命能續多久,下面討論的也適用于const T&):
    1. 函數不能返回對局部變量的引用(右值引用也不行),這是鐵的原則;
    2. 引用一旦建立(用一個名字hold住了臨時變量),例如T&& t = get_val();那么這個臨時變量的析構時機就是變量t退出其作用域的時候,因此下面的代碼是錯誤的:
        struct A {
            A(T&& t): _t(t) {};
            T&& _t;
        };
        A* pa = NULL;
        {
            T&& t = get_val();
            pa = new A(t);
        }
        pa->_t; //runtime crash, _t已經析構了
        
    std::move只做一件事:把左值轉成右值,因此T t(std::move(get_val()));不管什么情況下都能保證調用move constructor來構造t;
    c++0x里stl的各種容器都已經新增了move constructor,因此當你希望使用淺拷貝的時候可以借助std::move來達成所愿了,至于什么時候可以用淺拷貝,分兩種情況,有些情況編譯器會默認幫你去調用move constructor,但在你自己新定義的函數或者類成員方法里就需要你自己來判斷了,大的原則就是:這個變量只是傳遞過去就好,中間可以轉好幾道手,但在傳遞過程中不需要做修改;
    完美轉發(std::forward),談到這個就必須得談到通用引用(universal reference)、引用折疊(reference collapsing),其實這幾個概念是捆綁在一起的,而且只用在模板范疇內,而且只是為了解決下面這一種模式:
    template <typename T>
    void func2(T t) {
    }
    template <typename T>
    void func(T&& t) {
        func2(std::forward<T>(t));
    }
    上面這個到底完美在哪里?
    func(get_val()); //這個會導致最后是通過move constructor來構造func2函數里的參數t
    T t0 = get_val();
    T& t1 = t0;
    const T& t2 = get_val();
    T&& t3 = get_val();
    const T&& t4 = get_val();
    func(t0); func(t1); func(t2); func(t3); func(t4); //這5個都會導致最后是通過copy constructor來構造func2函數里的參數t,因為這個5個t*都是左值(有名字的就是左值);
        插播兩個你有可能費解的地方:
        1. func函數的參數是T&&, t0、t1都是左值,不是說不能用左值賦值給右值嗎?這就要提到引用折疊了(詳情可參見最后我推薦的文章),說白了因為func是個模板函數才能這么干;
        2. t3類型是T&&,func的參數也是T&&,把t3傳遞過去,居然還是調用copy contructor,因為t3是右值引用,它引用了一個右值,但它本身卻是左值,到了func函數內部,func函數只能知道它是個左值,了解不到它原本的面貌居然是個右值引用;如果還不理解,再看下下面:
        template <typename T>
        void print(T t) {
        }
        int x1 = 1; int& x2 = x1; const int& x3 = x1; int* x4 = &x1;
        分別用x{1..4}來調用print方法,你肯定知道x1、x2、x3到了print函數里,T就是int,只有x4會被print函數認為T是int*,引用這個概念在模板類型推導時是無法讓模板參數感知到的;此外print(T)和print(T&)是不能同定義的,編譯器會抱怨ambiguous,這個事實也能幫你多一些理解。
    如果想讓上面的這5個最終能通過move constructor來構造func2函數里的參數t,那么只要給每個都用func(std::move(t*))包裝下就可以了;
    再澄清下,func2函數的參數是類型T,并不是引用,因此無論如何都需要生成T的一個新實例,區別就是到底是通過copy constructor還是move constructor來生成了;
    所以,所謂的完美就是體現在了forward能把本來是左值的按左值來傳遞,本來是右值的按照右值來傳遞,具體來說就是作為中間環節的func函數內部實現過程中使用了func2(std::forward<T>(t));這句話,使得可以按照調用方實際的真實情況告知給func2函數如何構造參數t,這有什么好處呢,還是那句話:在適當的時機做合適的引導,讓編譯器幫你調用淺拷貝。
    除此之外,你完全可以忘掉這些玄乎其神的概念,所以只要會套用就可以了。
    以上是一些梗概性或結論性的東西,再結合下面這篇文章,把骨頭之外的血肉補上吧:
    https://codinfox.github.io/dev/2014/06/03/move-semantic-perfect-forward/

    posted on 2018-12-06 11:38 so true 閱讀(523) 評論(0)  編輯  收藏 所屬分類: C&C++

    主站蜘蛛池模板: 少妇中文字幕乱码亚洲影视| 国产成人A人亚洲精品无码| 99re6在线视频精品免费| 国产精品久久久久影院免费| 亚洲美国产亚洲AV| 女性无套免费网站在线看| 亚洲精品中文字幕| 国产一级一片免费播放| 一级特黄色毛片免费看| 国产成人综合亚洲亚洲国产第一页| 久久精品无码专区免费| 免费看国产精品3a黄的视频| 亚洲午夜精品久久久久久app| 成年女人午夜毛片免费看| 午夜亚洲国产理论片二级港台二级| 四虎影视精品永久免费| h在线看免费视频网站男男| 免费观看的a级毛片的网站| 美女视频黄频a免费大全视频| 精品国产日韩亚洲一区| 男人都懂www深夜免费网站| 亚洲高清日韩精品第一区| 久久久久久久国产免费看| 久久青草亚洲AV无码麻豆| 免费下载成人电影| 久久久久亚洲AV无码去区首| 亚洲男人的天堂在线va拉文| 日本免费一区二区久久人人澡| 亚洲中文久久精品无码1| 国产乱子伦精品免费女 | 亚洲av日韩专区在线观看| 亚洲中久无码不卡永久在线观看| 国产精品免费无遮挡无码永久视频 | 婷婷亚洲综合五月天小说在线| 亚洲宅男天堂在线观看无病毒| 久视频精品免费观看99| 亚洲av无码一区二区三区天堂| 中文字幕久久亚洲一区| 无人在线观看完整免费版视频| 成人一级免费视频| 亚洲人成综合网站7777香蕉|