内容学习自:爱编程的大丙
一、move
因为存在不能用左值初始化右值引用的问题,所以可以借助std::move()函数将左值转化为右值。这个函数也具有移动语义,即将对象状态或者所有权从一个对象转移到另一个对象,没有进行内存拷贝。
std::move 很像类型转换 static_cast<T&&>(lvalue);
使用方法:
class test
{
public:
test(){}
};
void main()
{
test t;
test && t1 = t; //error 不能将左值付给右值引用
test && t2 = move(t);//ok
}
应用在一些容器上,为了提升效率,我们就可以:
list<string> str;
str.push_back("我是");
str.push_back("火影");
list<string> str1 = str;//效率差
list<string> str2 = move(str);
像这样,如果一个对象内部有较大内存或者动态数组时,使用move就不会有代价。我们这时在给他写上移动构造函数,和移动语义赋值函数(T&& T::operator = (T&& rhs)),在构造和赋值的时候就可以最大化利用资源,因为都只需要接收右值引用参数。
二、forward
完美转发,说是在用右值引用做参数形参的时候,在函数内部转发此函数给其他函数就会变成左值。使用std::forward()可以实现完美转发
template<typename T>
void print_1(T& t)
{
cout << "l-value:" << t << endl;
}
template<typename T>
void print_1(T&& t)
{
cout << "r-value:" << t << endl;
}
template<typename T>
void forwardTest(T&& t)
{
print_1(t);
print_1(move(t));
print_1(forward<T>(t));
cout << endl;
}
void main()
{
#if 1
int num = 1;
forwardTest(2);
forwardTest(num);
forwardTest(forward<int>(num));
forwardTest(forward<int&>(num));
forwardTest(forward<int&&>(num));
#endif
}
?解释:
forwardTest(2);
- 已命名的右值会被视为左值
- 已命名的右值会被视为左值,通过move又变为了右值
- forward 的模板参数为右值引用,最终得到一个右值,实参为 `右值`
forwardTest(num);
- 实参为左值
- move将左值变为右值
- 模板是左值引用所以是左值
forwardTest(forward<int>(num));
- 已命名的右值 v,编译器会视为左值处理,实参为左值
- 已命名的右值编译器会视为左值处理,通过 move 又将其转换为右值,实参为右值
- forward 的模板参数为右值引用,最终得到一个右值,实参为右值
forwardTest(forward<int&>(num));
- 实参为左值
- 通过 move 将左值转换为右值,实参为右值
- forward 的模板参数为左值引用,最终得到一个左值,实参为左值
forwardTest(forward<int&&>(num));
- 已命名的右值 v,编译器会视为左值处理,实参为左值
- 已命名的右值编译器会视为左值处理,通过 move 又将其转换为右值,实参为右值
- forward 的模板参数为右值引用,最终得到一个右值,实参为右值
|