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