--- tags: CSE --- ## std::move consider a common scene: ```cpp= template<class T> class vector { T* arr; // ... }; vector<Data> v1; fillWithLotsData(v1); ``` now i want a new vecotor, ```v2```, having the same content in ```v1```, and the ```v1``` is no longer used. i may have done this: ```cpp= vector<int> v2(v1); ``` constructing ```v2``` by copying from ```v1```. but the data size in ```v1``` is large, the cost to do that is too expensive. the better way doing that is just copy the pointer: ```cpp= v2.arr = v1.arr; v1.arr = nullptr; // this line is important, // because the pointed resource may be released, // when v1 calls its destructor. ``` but with obvious reason, the class member, ```arr```, shouldn't be used like this. so, how to have a nice, short, and clever solution? remember the definition of rvalue? __those who can be used only once__. because it's just used once, we can take over the content of it. ```cpp= template<class T> class vector { T* arr; // ... vector(const vector& src) // copy constructor, take only lvalue // need to copy from a lvalue, since it may be used more than once. { this->arr = new T[src.n]; copy(src, this); } vector(vector&& src) // move constructor, take only rvalue // no needs to copy, since it's just used once. { this->arr = src.arr; src.arr = nullptr; } }; vector<Data> v1; fillWithLotsData(v1); // ... vector<Data> v2(v1); // too expensive! vector<Data> v2(MakeItRvalue(v1)); // this is better, since it's called move constructor. // after this, v1 can't be used. ``` the pseudo function, ```MakeItRvalue```, is what ```std::move``` meant to do, make it rvalue. an possible implementation of ```std::move```: ```cpp= template<class T> typename std::remove_reference<T>::type&& move(T&& t) noexcept { using retType = typename std::remove_reference<T>::type&&; return statis_cast<retType>(t); } // c++ 14 ver. template<class T> decltype(auto) move(T&& t) noexcept { using retType = typename std::remove_reference_t<T>&&; return statis_cast<retType>(t); } ``` the "```&&```" part of the function's return type implies that ```std::move``` returns an rvalue reference. but if the deduced type, ```T```, is a lvalue reference, ```T&&``` will collapse to ```T&```. to prevent that, ```std::remove_reference``` is applied to ```T```. thus, no matter what type is deduced, ```std::move``` returns a rvalue reference. and that's important, because a rvalue reference returned by a function is xvalue which can be used to initialize an rvalue reference (or a const lvalue reference). ## a possible mistake u need to know ```cpp= class A() { public: explicit A(const std::string text) : val(std::move(text)) // this code doesn't do what it seems to do! { // ... } private: std::string val; }; ``` the initialization of ```val``` is actually by copying actually. why? ```std::move()``` casts ```text``` to rvalue, but the [CV-qualifier](https://en.cppreference.com/w/cpp/language/cv) is preserved, the type of ```std::move(text)``` is rvalue ```const std::string```. take a look at the string class: ```cpp= class string { public: // ... string(const string& rhs); // copy ctor string(string&& rhs); // move ctor // ... } ``` the move constructor takes a rvalue, but not a "```const```" rvalue. (compiler cannot ignore the ```const```ness, because it's dangerous.) therefore, the one takes ```std::move(text)``` is copy constructor which takes a ```const std::string&```. ## std::forward also consider a common scene: ```cpp= class data_t { // some huge amount data }; class A { data_t data; public: // some other ctors ... // copy data A(const data_t& d) { std::cout << "copy" << std::endl; } // move data A(data_t&& d) { std::cout << "move" << std::endl; } }; template<class T> A MakeA(T&& x) { return A(x); } data_t d1, d2; fillWithData(d1); fillWithData(d2); MakeA(d1); // expect to call copy ctor MakeA(std::move(d2)); // expect to call move ctor MakeA(data_t{}); // expect to call move ctor ``` we expect to see ``` copy move move ``` but the truth is, ``` copy copy copy ``` why? because the ```x``` in ```MakeA``` is a lvalue! remember how to distinguish lvalue from rvalue? __those who can be used more than once__ is lvalue. ```x``` in ```MakeA``` can definitely used more than once, thus, it's a lvalue. but how to solve this problem? surely we can't use ```std::move```. we must have a function, ```keepValCate()```, which keeps the value categories the same. ```cpp= template<class T> A MakeA(T&& x) { return A(keepValCat(x)); } ``` ```std::forward``` is the pesudo function, ```keepValCate```, but a little different. not so convenient. an possible implementation of ```std::forward```: ```cpp= template<class T> T&& forward(typename std::remove_reference<T>::type& t) noexcept { return static_cast<T&&>(t); } template<class T> T&& forward(typename std::remove_reference<T>::type&& t) noexcept { // this static_assert can be ignored. static_assert(!std::is_lvalue_reference<T>::value, "Can not forward an rvalue as an lvalue."); return static_cast<T&&>(t); } ``` to explain how it works, we need an example: ```cpp= template<class T> A MakeA(T&& x) { return A(std::forward<T>(x)); // the <T> is the key point. } ``` in ```MakeA```, if the value passed in is a xvalue or pvalue, ```T``` will be deduced as rvalue reference. if passed in is a lvalue, ```T``` will be deduced as lvalue reference. ```std::forward``` return the type ```T&&```, which is a universal reference. if ```T``` is lvalue reference, ```T&&``` will collapse to lvalue reference. if ```T``` is rvalue reference, ```T&&``` will be just rvalue reference, and this is important. since a rvalue reference returned by function is a xvalue, which, in this case, can be captured by move constructor. ## a possible mistake u need to know don't write ```std::forward<somType&>(something)```, if you don't have special reasons, because```someType&``` will make ```std::forward``` return lvalue reference, always. for example: ```cpp= void f(int&& x) { std::cout << std::boolalpha << std::is_lvalue_reference_v<\ decltype(std::forward<int&>(x))\ > << std::endl; } int z = 1; f(0); f(std::move(z)); ``` the ouput is ``` true true ``` no matter what value passed in, the result is always lvalue reference. --- reference: - Effective Modern C++ 1/e, Scott Meyers - https://stackoverflow.com/questions/27501400/the-implementation-of-stdforward