標籤:return clu color sys == ++ 重載 private end
c++11 移動語意
#define _CRT_SECURE_NO_WARNINGS#include <iostream>#include <string>#include <vector>#include <map>// C++中還有一個被廣泛認同的說法,那就是可以取地址的、有名字的就是左值,反之,不能取地址的、沒有名字的就是右值。// 相對於左值,右值表示字面常量、運算式、函數的非引用傳回值等。/*右值引用是用來支援轉移語義的。轉移語義可以將資源 ( 堆,系統對象等 ) 從一個對象轉移到另一個對象,這樣能夠減少不必要的臨時對象的建立、拷貝以及銷毀,能夠大幅度提高 C++ 應用程式的效能。臨時對象的維護 ( 建立和銷毀 ) 對效能有嚴重影響。轉移語義是和拷貝語義相對的,可以類比檔案的剪下與拷貝,當我們將檔案從一個目錄拷貝到另一個目錄時,速度比剪下慢很多。通過轉移語義,臨時對象中的資源能夠轉移其它的對象裡。*//*移動語意定義: 在現有的 C++ 機制中,我們可以定義拷貝建構函式和賦值函數。要實現轉移語義,需要定義轉移建構函式,還可以定義轉移賦值操作符。對於右值的拷貝和賦值會調用轉移建構函式和轉移賦值操作符。如果轉移建構函式和轉移拷貝操作符沒有定義,那麼就遵循現有的機制,拷貝建構函式和賦值操作符會被調用。普通的函數和操作符也可以利用右值引用操作符實現轉移語義。*/class MyString{public: MyString(const char *tmp = "abc") {//普通建構函式 len = strlen(tmp); //長度 str = new char[len+1]; //堆區申請空間 strcpy(str, tmp); //拷貝內容 cout << "普通建構函式 str = " << str << endl; } MyString(const MyString &tmp) {//拷貝建構函式 len = tmp.len; str = new char[len + 1]; strcpy(str, tmp.str); cout << "拷貝建構函式 tmp.str = " << tmp.str << endl; } //移動建構函式 //參數是非const的右值引用 MyString(MyString && t) { str = t.str; //拷貝地址,沒有重新申請記憶體 len = t.len; //原來指標置空 t.str = NULL; cout << "移動建構函式" << endl; } MyString &operator= (const MyString &tmp) {//賦值運算子多載函數 if(&tmp == this) { return *this; } //先釋放原來的記憶體 len = 0; delete []str; //重新申請內容 len = tmp.len; str = new char[len + 1]; strcpy(str, tmp.str); cout << "賦值運算子多載函數 tmp.str = " << tmp.str << endl; return *this; } //移動賦值函數 //參數為非const的右值引用 MyString &operator=(MyString &&tmp) { if(&tmp == this) { return *this; } //先釋放原來的記憶體 len = 0; delete []str; //無需重新申請堆區空間 len = tmp.len; str = tmp.str; //地址賦值 tmp.str = NULL; cout << "移動賦值函數\n"; return *this; } ~MyString() {//解構函式 cout << "解構函式: "; if(str != NULL) { cout << "已操作delete, str = " << str; delete []str; str = NULL; len = 0; } cout << endl; }private: char *str = NULL; int len = 0;};MyString func() //返回普通對象,不是引用{ MyString obj("mike"); return obj;}void mytest(){ MyString &&tmp1 = func(); //右值引用接收 MyString tmp2("abc"); //執行個體化一個對象 tmp2 = func(); return;}int main(){ mytest(); system("pause"); return 0;}
c++11 移動語意