左值不一定是lhs的例子
string s{};
s+s = s;
1.move
万能引用,然后转型成去掉ref的type&&
template <typename T>
typename remove_reference<T>::type&& move(T&& arg) noexcept
{
return static_cast<typename remove_reference<T>::type&&>(arg);
}
// Simple move constructor
A(A&& arg) : member(std::move(arg.member)) // the expression "arg.member" is lvalue
{}
// Simple move assignment operator
A& operator=(A&& other) {
member = std::move(other.member);
return *this;
}
2.如何写移动构造
2.1.如果不涉及直接资源,如raw ptr,直接用default
rule of zero
2.2.直接涉及资源,手写
此时注意,在传入参数时调用函数时是右值(calling scope),但是函数体内w实际是一个左值。
在move资源时,如果不nulltify将忘的右值,其可能会把被转移的资源给释放了(析构函数)。
当然也可以用std::exchange,把被移动的对象赋0。此外,可以加上noexpect,对速度有提升。
实际上move一个int就是复制一个int,所以不需要设为0,因为这类build-in类型并没有移动赋值和移动构造。
3.如何写移动赋值
写移动赋值,需要记得清理被赋值对象的资源。
使用swap虽然elegant,但是会把旧的资源转给w。
不适用于self-move的情况(加个if判断就好),不过self-move就是不合逻辑的操作。
3.1.rule of 4.5
可以使用在raii那集中的方法,将两个赋值函数合并
4.什么情况编译器会自动生成特殊成员函数(构造,赋值...)
其实是一个rule of thumb的延申,如果自定义了一个特殊成员函数(包括default和delete),你就要手写其他4成员函数(如果不需要move也要删除移动构造和移动赋值函数)
5.函数设计
移动并不一定是最有效的方法,那如何高效地返回或输入数据。比如数组不好移动,可以用f(T&)来返回数据。unique_ptr是f(x),但是调用时需要move,用右值来转移所有权到x
6.forwarding reference
forwarding reference: 通过模板template
引用折叠能帮助推导出(Widget &是模板推导出的,手写一个Widget& &&是不合法的操作)
- T&& && ->右值引用
- T& && ->左值引用
两种引用都能被保留。template
7.perfect forwarding
forwarding reference能对左值和右值以及左值引用和右值引用进行区分,但是还是没有解决一个问题,在进入函数体后,T&& t实际成了一个命名了的左值,这时候用来初始化实际是一个调用了拷贝构造。但是我们也不能直接使用move,我们需要的是一个有条件的move来解决这个问题(只对右值进行move)。
使用std::forward能解决以上问题。
8.Overloading with forwarding reference
const T& 优先级都不高
优先 完全匹配上的非模板函数
const T&& 是const 右值引用,不是万能引用
template <typename T> void f (T&&);
template <typename T> void g (const T&&);
s x;
f (s ()); // Ok, T = s
f (x); // Ok, T = s&
g (s ()); // Ok, T = s
g (x); // Error, binding lvalue to rvalue, T = s
https://www.codesynthesis.com/~boris/blog/2012/07/24/const-rvalue-references/
9.移动语义纠错
需要改成forward
T是类模板,这里的T&&是一个右值引用,所以应该使用move
不能对一个变量forward两次,不然在右值的情况下就不合理了,第一次应该改为拷贝
不需要return move(t),让编译器帮你做(N)RVO
如果能不使用命名变量,那么在c++17的标准下会保证执行RVO
不要返回&&,这就是返回一个要被销毁的局部变量的引用-> dangling reference
注意,如果T是左值,万能引用推导出的是T&,所以要remove_reference