Rvalue references are
a new reference type introduced in C++0x that help solver the problem of
unnecessary copying and enable
perfect forwarding.
When the right-hand side of an assignment is an rvalue, then the left-hand side object can 'steal' resource from the right-hand side object rather than performing a separate allocation
, thus enabing
move semantics.
(右值引用是C ++ 0x中引入的新引用類型,可幫助解決沒必要要的複製問題並實現完美轉發。 當賦值的右側是右值時,則左側對象能夠從右側對象竊取資源,而沒必要執行單獨的分配,從而能夠實現移動語義。)ios
以 int 測試:c++
int a = 9; int b = 4; a = b; // OK b = a; // OK a = a + b; // Ok a+b = 42; // error: lvalue required as left operand of assignment
以 string 測試:ide
string s1("Hello "); string s2("Word!"); s1 + s2 = s2; // 居然編譯經過!! string() = "Word"; // 居然能夠對 temp object 賦值!!
以 complex 測試:函數
complex<int> c1(3, 8); complex<int> c2(1, 9); c1 + c2 = c2; // 居然編譯經過! complex<int>() = complex<int>(4,9); // 居然能夠對 temp object 賦值!!
已知 (a+b) 、臨時對象爲右值,只能出如今賦值符號右邊,但 string,complex 的表現與咱們認知不一樣。測試
C++ with its user-defined types has introduced some subtleties regarding modifiability and assignability that cause this definition to be incorrect.
(C ++及其用戶定義類型引入了一些與可修改性和可分配性有關的細微之處,這些細微之處致使該定義不正確。)ui
總結:this
int foo() { return 5; } int x = foo(); // OK int *p = &foo(); // error: lvalue required as unary ‘&’ operand foo() = 7; // error: lvalue required as left operand of assignment
對 Rvalue 取 reference 不能夠。沒有所謂的 Rvalue reference(c++0x 以前)。spa
當 Rvalue 出如今 operator=(copy assignment) 的右側,咱們認爲對其資源進行「偷取/搬移(move)」而非拷貝(copy)是能夠的,合理的。
那麼:指針
僞代碼:code
using namespace std; class MyString { private: char *_data; public: // copy ctor MyString(const MyString &str) : initializer_list { // ... } // move cpor MyString(const MyString &&str) noexcept : initializer_list // 注意這裏 !! { // ... } // copy assignment MyString& operator=(const MyString &str) { return *this; } // move assignment MyString& operator=(const MyString &&str) noexcept // 注意這裏 !! { return *this; } }; template <typename M> void test_moveable(M c, long value) { typedef typename iterator_traits<typename M::iterator>::value_type Vtype; char buf[10] = {0}; clock_t timeStart = clock(); for (long i=0; i<value; ++i) { snprintf(buf, 10, "%d", rand()); // 隨即數轉爲字符串 auto ite = c.end(); // 定位到尾部 c.insert(ite, Vtype(buf)); // 插入 注意這裏!! output_static_data(*(c.begin())); // copy/move ctor 被調用次數 } cout << "millo - second : " << (clock() - timeStart) << endl; cout << "size() = " << c.size() << endl; M c1(c); // copy ctor M c2(std::move(c1)); // move ctor 注意這裏!! (必須確保之後再也不使用c1,由於c1 源數據被偷走) c1.swap(c2); }
說明:
iterator insert(const_iterator __position, const value_type& __x); iterator insert(const_iterator __position, value_type&& __x) { return _M_insert_rval(__position, std::move(__x)); }
M c2(std::move(c1));
具體發生在指針上
-
You need to inform C++ (specifically std::vector) that your move constructotr and destructor does not throw, Then the move constructor will be called when the vector grows.
(你須要通知C ++(特別是std :: vector),你的move構造函數和析構函數不會拋出異常,而後,當vector增大時,將調用移動構造函數。)
文件:Test.cpp
#include <iostream> using namespace std; void process(int &i) { cout << "process(int&): " << i << endl; } void process(int &&i) { cout << "void process(int &&i): " << i << endl; } void forward(int &&i) { cout << "forward(int &&i): " << i << endl; process(i); } int main() { int a = 0; process(a); process(1); process(move(a)); cout << "**************" << endl; forward(2); // 注意這裏輸出!! 右值引用在數據傳遞時丟失了信息 forward(move(a)); // 注意這裏輸出!! 右值引用在數據傳遞時丟失了信息 // forward(a); // error: cannot bind rvalue reference of type ‘int&&’ to lvalue of type ‘int’ return 0; }
輸出:
process(int&): 0 void process(int &&i): 1 void process(int &&i): 0 ************** forward(int &&i): 2 process(int&): 2 forward(int &&i): 0 process(int&): 0
任何的函數內部,對形參直接使用,都會被按照左值進行處理。
Perfect forwarding allows you to write a single function template that takes n arbitrary arguments and forwards them transparently to another arbitrary function. The nature of the argument(modifiable, const, lvalue or rvalue) is preserved in this forwarding process.
(完美轉發使您能夠編寫一個帶有n個任意參數的函數模板,並將其透明地轉發給另外一個任意函數。 在此轉發過程當中保留了參數的性質(可修改,const,左值或右值)。)
template <typename T1, typename T2> void functionA(T1 &&t1, T2 &&t2) { functionB(std::forward<T1>(t1), std::forward<T2>(t2)); }
文件:Test.cpp
#include <iostream> using std::cout; using std::endl; using std::move; void process(int &i) { cout << "process(int&): " << i << endl; } void process(int &&i) { cout << "void process(int &&i): " << i << endl; } template <typename T> void forward(T &&i) { cout << "forward(T &&i): " << i << endl; process(std::forward<T>(i)); } int main() { int a = 0; process(a); process(1); process(move(a)); cout << "**************" << endl; forward(2); // 注意這裏輸出!! forward(move(a)); // 注意這裏輸出!! return 0; }
輸出:
process(int&): 0 void process(int &&i): 1 void process(int &&i): 0 ************** forward(T &&i): 2 void process(int &&i): 2 forward(T &&i): 0 void process(int &&i): 0
文件:move.h
/** * @brief Forward an lvalue. * @return The parameter cast to the specified type. * * This function is used to implement "perfect forwarding". */ template<typename _Tp> constexpr _Tp&& forward(typename std::remove_reference<_Tp>::type& __t) noexcept { return static_cast<_Tp&&>(__t); } /** * @brief Forward an rvalue. * @return The parameter cast to the specified type. * * This function is used to implement "perfect forwarding". */ template<typename _Tp> constexpr _Tp&& forward(typename std::remove_reference<_Tp>::type&& __t) noexcept { static_assert(!std::is_lvalue_reference<_Tp>::value, "template argument" " substituting _Tp is an lvalue reference type"); return static_cast<_Tp&&>(__t); } //----------------- /** * @brief Convert a value to an rvalue. * @param __t A thing of arbitrary type. * @return The parameter cast to an rvalue-reference to allow moving it. */ template<typename _Tp> constexpr typename std::remove_reference<_Tp>::type&& move(_Tp&& __t) noexcept { return static_cast<typename std::remove_reference<_Tp>::type&&>(__t); } // ---------------- /// remove_reference template<typename _Tp> struct remove_reference { typedef _Tp type; }; template<typename _Tp> struct remove_reference<_Tp&> { typedef _Tp type; }; template<typename _Tp> struct remove_reference<_Tp&&> { typedef _Tp type; };