1.右值引用的舉例測試
#include <iostream> using namespace std; //建立一個測試類 class A { public: A() : m_a(55) { } int m_a; }; void funcA(A&& param) // 右值引用引數,只接受右值 { cout << param.m_a << endl; // param與a的地址一致,僅僅只是取了一個新名字 } int main() { A a; funcA(move(a)); //必須將其轉換為右值 cout << a.m_a << endl; //正常列印,所以std::move並沒有移動的能力 return 0; }
2.左值和右值引用的舉例測試,以及引出萬能引用
構造一組過載函式,分別接受右值,和左值的引數,還有const A&的引數過載函式。
void funcA(const A& param)//既可以接受右值引用,也可以接受左值引用,但是有一個隱式轉換const A& void funcA(A& param)// 接受左值引用 void funcA(A&& param) // 接受右值引用
const A& param既可以接受右值引用,也可以接受左值引用,但是存在一個隱式轉換,const使用受限制。
#include <iostream> using namespace std; //建立一個測試類 class A { public: A() : m_a(55) // 建構函式 { cout << "Constructor" << endl; } A(const A & other) : m_a(55) // copy建構函式 { cout << "Copy Constructor" << endl; if (this == &other) { return; } this->m_a = other.m_a; } A& operator=(const A& other) // 賦值建構函式 { cout << "= Constructor" << endl; if (this == &other) { return *this; } this->m_a = other.m_a; return *this; } int m_a; }; void test(A&& pa) //測試是否為右值 { cout << "只接受右值" << endl; } void funcA(const A& param) // 既可以接受右值引用,也可以接受左值引用,但是有一個隱式轉換const A& { //test(param); //編譯不過,param可以接受右值,但是param被轉換為const左值 //test(std::forward<A>(param)); //編譯不過,param可以接受右值,但是param被轉換為const左值 cout << param.m_a << endl; } void funcA(A& param) // 接受左值引用 { //test(param); //編譯不過,param可以接受右值,但是param被轉換為左值 test(std::forward<A>(param)); //編譯通過,通過forward轉發 cout << param.m_a << endl; } void funcA(A&& param) // 接受右值引用 { //test(param); //編譯不過,param被轉換為左值 test(std::forward<A>(param)); //編譯通過,通過forward轉發 cout << param.m_a << endl; } int main() { A a; const A& b = a; funcA(a); funcA(move(a)); funcA(b); cout << a.m_a << endl; //正常列印,所以std::move並沒有移動的能力 return 0; }
對此C++11引入了萬能引用的概念,使得不需要那麼多的過載函式,既可以接受右值引用,也可以接受左值引用。但是函式內部,再需要呼叫一個左值或者右值的函式時,我們就得需要forward模版類。
#include <iostream> using namespace std; //建立一個測試類 class A { public: A() : m_a(new int(55)) // 建構函式 { cout << "Constructor" << endl; } A(const A & other) : m_a(new int(55)) // copy建構函式 { cout << "Copy Constructor" << endl; if (this == &other) return; this->m_a = other.m_a; } A& operator=(const A& other) // 賦值建構函式 { cout << "= Constructor" << endl; if (this == &other) return *this; this->m_a = other.m_a; return *this; } int* m_a; }; void test(A&& pa) //測試是否為右值 { cout << "只接受右值" << endl; } void test(A& pa) //測試是否為左值 { cout << "只接受左值" << endl; } template<class T> void funcA(T&& param) { test(std::forward<T>(param)); //編譯通過,通過forward完美轉發 cout << *param.m_a << endl; } int main() { A a; funcA(a); funcA(move(a)); cout << *a.m_a << endl; //正常列印,所以std::move並沒有移動的能力 return 0; }
3.移動建構函式的引出
以上的所有特性,所能體現出來的是我們對於臨時變數的使用,儘可能的使用中間生成的臨時變數,提高效能,所謂的榨取最後的效能。移動建構函式注意的兩點
1.呼叫移動建構函式時引數(被移動者)必須是右值。
2.呼叫移動建構函式後被移動者就不能再被使用。
#include <iostream> using namespace std; //建立一個測試類 class A { public: A() : m_a(new int(55)) // 建構函式 { cout << "Constructor" << endl; } A(const A & other) : m_a(new int(55)) // copy建構函式 { cout << "Copy Constructor" << endl; if (this == &other) { return; } this->m_a = other.m_a; } A& operator=(const A& other) // 賦值建構函式 { cout << "= Constructor" << endl; if (this == &other) { return *this; } this->m_a = other.m_a; return *this; } A(A&& other) : m_a(other.m_a) // 移動建構函式,引數是一個右值, { cout << "Move Constructor" << endl; if (this == &other) { return; } other.m_a = nullptr; //移動後將被移動的物件資料清空 } int* m_a; }; void test(A&& pa) //測試是否為右值 { cout << "只接受右值" << endl; } void test(A& pa) //測試是否為左值 { cout << "只接受左值" << endl; } template<class T> void funcA(T&& param) { test(std::forward<T>(param)); //編譯通過,通過forward完美轉發 cout << *param.m_a << endl; } int main() { A a; funcA(a); funcA(move(a)); A b(move(a)); //呼叫移動建構函式,新的物件是b物件 cout << *a.m_a << endl; //資料已被移動,程式崩潰 return 0; }