std move的原理與實現,右值引用的深入理解

2022-03-26 14:32:41 字數 2603 閱讀 7114

這次我真的懂了。。。。

首先c++11引入了右值引用 &&

『&&』這個要連起來看,是乙個整體,c++多了乙個關鍵字而已。

不是引用的引用。是船新的一種語法。那有什麼用呢?

額,引數的型別又多了一種!

void fun(int t)

void fun(int& t)

void fun(int && t)

void fun(int* t)

之前的引數,值傳遞,引用,指標。現在呢?多了乙個叫 「右值引用」的玩意,多了一種引數型別的選擇。僅此而已。

那他們號稱的右值引用速度快,代價小呢?

額,這個需要庫作者自己去實現的,跟c++語言本身無關。

舉兩個例子

void fun(int & t)

t= 2;

void fun(int && t)

cout<

x++;

x--;

這個右值引用的fun函式就更複雜了嘛,沒有說一定要簡單啊,完全由庫作者決定的。

當然,現在的庫作者對右值引用的函式往往做了記憶體轉移的操作(尤其是移動建構函式與移動賦值函式)

class

a a(a&a)

a(a&&a)

~a()

private

:

int * p=nullptr;

};

如上,對於右值引用建構函式,僅僅是轉移了記憶體,並讓被轉移的指標置空。當然,這個右值引用建構函式具體的實現還是由庫作者決定的。

另外,如果沒有右值引用建構函式,會自動呼叫拷貝建構函式。

這裡說到了轉移,嗯,翻譯下就是move。move這個函式看上去是專門轉移記憶體的。實際上是錯誤的。。

move僅僅是進行了乙個 右值引用 的強制轉換。

對於強制轉換,你可能會寫

templatet && make_move(t&&t)  //當然真正的是std::move,我這裡取名實現類似的move。make_move跟make_love沒有關係哈,純粹的偶然。。

額,這是啥,t &&轉換成t&& ,看上去啥都沒做嘛。

首先:對於make_move(t&& t)中的 t,說明make_move的函式引數是右值引用,但不代表t是右值引用。t可能是左值。額,越來越頭大了。

想起了「書越讀越厚,然後越讀越薄」。其實我自己對這個的理解過程也超過了2年多,這次真的搞懂了!!

上例子緩緩

int x =10;

make_move(x)  //此時x是左值,什麼叫左值,就是可以取位址的變數。&x有意義的變數。

make_move(20) //20是真正的右值。

看上去這個時候make_move體現出了意義,把t強轉成右值引用了。

但讀過  模板型別推倒、auto推導 後,我們知道,左值(或引用)的強制右值轉換返回是個左值引用。簡單的如下:

於是,經過make_move函式後返回的是int & 而不是int &&。

那怎麼才能得到真正的int && 呢。需要加上traits。

templatetypename remove_reference

::type && make_move(t&&t)

typename 是為了告訴編譯器type是乙個型別,這個在stl很常見。

舉個例子

struct a

typedef unsigned size_t;

static size_t value;

我們訪問value      使用a::value

我們訪問size_t      使用a::size_t  那麼size_t到底是值還是型別,編譯器不明白。

所以我們會用 typename a::size_t ;  (typename 翻譯型別名字,就是表明該變數是個型別)

remove_reference::type 就是去掉t的引用後的型別,再加上&&

就是真的t的右值引用了。

如你所見,這個也基本是std::move幹的事。因此move並沒有轉移記憶體還是啥的,甚至沒有轉移的語義。只是一種型別的強制轉換。所以如果命名為rvalue_cast,我也能早點懂得。

std::vectorve;

std::string str="msg";

ve.push_back(str);

ve.push_back(std::move(str)); //內部實現可能是這樣子的

void push_back(str)  

t temp (str);  //呼叫值拷貝構造

__insert(temp);

ve.push_back(std::move(str));

t temp (t) ;  //呼叫右值拷貝構造

__insert(temp);

確實會比ve.push_back(str)快一點點,std::string的右值拷貝構造直接轉移了記憶體。

最終看起來像是move的功勞,也實現了轉移的語義。

但實際上是std::string的右值拷貝構造直接轉移了記憶體。當然感謝move,但str真的從左值變成了右值引用。

the  end

std move和右值引用

右值引用允許程式設計人員去避免不必要的記憶體拷貝,從而提高效能。我們知道如果乙個類a的成員變數中有指標,那麼就要考慮深拷貝和淺拷貝了,深拷貝通常要實現下面幾個函式 建構函式 拷貝構造 賦值操作符 這樣做是沒問題的,但是會帶來乙個問題,會造成一些沒必要的拷貝,如 std string str hell...

std move 強制轉化為右值

在c 11中,標準庫在中提供了乙個有用的函式std move,這個函式的名字具有迷惑性。實際上std move並不能移動任何東西,它唯一的功能是將乙個左值強制轉化為右值引用,繼而我們可以通過右值引用使用該值,以用於移動語義。從實現上講,std move基本等同於乙個型別轉換 static cast ...

C 11 右值引用以及std move

int和int 是什麼?都是型別。int是整數型別,int 則是整數引用型別。相同int 也是乙個型別。兩個引號 是c 11提出的乙個新的引用型別。記住,這是乙個新的型別。默念 10次吧。假設你記住這個新型別,那麼非常多疑問都能迎刃而解。而且對 effective modern c 說到的void ...