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; };