這次我真的懂了。。。。
首先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_referencetypename 是為了告訴編譯器type是乙個型別,這個在stl很常見。::type && make_move(t&&t)
舉個例子
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 ...