- lvalue and rvalue
- Effective Modern C++中相关条款笔记总结
- Item 23: Understanding std::move and std::forward
- Item 24:Distinguish universal references from rvalue references
- Item 25:Use std::move on rvalue references, std::forward on universal references
- Item 26: Avoid overloading on universal references
- Item 27: Familiarize yourself with alternatives to overloading on universal references.
- Item 28: Understand reference collapsing
- Item 29: Assume that move operations are not present, not cheap, and not used
- Item 30: Familiarize yourself with perfect forwarding failure cases
- 参考
lvalue and rvalue
在概念上,右值对应于从函数返回的临时对象,而左值对应于可以引用的对象,无论是通过名称还是通过跟随指针或左值引用。一种判断表达式是左值还是右值的方法是:如果能得到其地址,那么它是左值,否则其是右值。
注意:一个表达式的类型和这个表达式本身是左值还是右值无关。
Effective Modern C++中相关条款笔记总结
Item 23: Understanding std::move and std::forward
要点
1、std::move
move semantic使得编译器将代价昂贵的copy操作替换为相对代价低的move。move semantics使得move-only类型的创建成为可能,比如std::unique_ptr,std::future,std::thread。
实际上std::move并没有移动任何东西。它做的其实是一个类型转换工作。就是将输入转型为rvalue。
2、std::forward
std::forward和std::move类似,比较大的区别就是std::forward是有条件的类型转换,
只有当参数是和rvalue绑定时将其转型为rvalue,否则不做转换。
Item 24:Distinguish universal references from rvalue references
要点
1、判断原则
A、当函数的模板参数有着T&&的形式,并且有推导类型T,或者一个对象被声明为auto&&,那么它就是一个universal reference。
B、如果type的声明的格式并不完全是type&&,或者类型推断没有发生,那么type&&表示的就是rvalue reference。
C、对于universal reference,如果它被rvalue初始化,它就是rvalue,与之对应,如果被lvalue初始化,其就是lvalue。
Item 25:Use std::move on rvalue references, std::forward on universal references
要点
1、当将rvalue reference转发给其它函数时,其应该被无条件转型为rvalue,即用std::move,因为它总是被rvalues限制,而将universal referencies转发给其它函数时,应该有条件地转型,即使用std::forward,因为它可能是lvalues。
注意1为什么不在任何情况下都使用std::forward?尽管使用std::forward对于rvalue references也能产生正确的行为,但是这样源代码冗长也容易出错。
注意2对universal references使用std::move会对lvalues造成意外的修改,更应该避免。
2、当一个函数按值返回时,如果是返回一个与 universal reference或者rvalue reference绑定的对象,那么在返回时可以对其施加std::forward或者std::move操作,这样效率更高
注意:即便该对象不支持move操作也没有任何副作用,因为如果不支持的话会自动调用该对象的拷贝构造函数完成copy。
3、不要将std::move或者std::forward应用到local object
原因详见P174,和编译器的返回值优化有关。
Item 26: Avoid overloading on universal references
要点看原书比较清楚(没太看懂。)
1、对通用引用进行重载往往导致其被调用的次数比预期要多很多。
2、完美转发的构造函数特别有问题,因为它们通常比拷贝构造函数更适合非常量lvalue,并且它们可以劫持派生类调用到其基类的拷贝和移动构造函数
Item 27: Familiarize yourself with alternatives to overloading on universal references.
Item 28: Understand reference collapsing
要点
1、
2、在C++中引用的引用是违法的
3、但是当lvalue传入一个以universal reference为类型的模板时
4、reference collapsing规则
在允许reference collapsing的情况下,如果两个reference中,任一个是lvalue reference,则结果是lvalue reference,否则结果是rvalue reference。
实际上,std::forward就是根据这个机制实现的。
5、深入理解universal reference
实际上,universal reference不是一种新引用,它是rvalue reference在以下条件满足时的一种特殊情况:
条件1类型推导区分左值和右值。类型T的左值推导为类型 T&,类型T的右值推导为类型 T。
条件2发生了reference collapsing。
6、reference collapsing发生的情况
情况1模板实例化
情况2auto类型生成
情况3生成、使用typedef 和 使用别名声明
情况4使用decltype
Item 29: Assume that move operations are not present, not cheap, and not used
要点
1、在以下情况下,std::move不会带来任何好处。
No move operations
Move not faster
Move not usable
Source object is lvalue
2、最好假设move操作不存在,不高效,没用过。只有在类型明确或者支持move语义时不需要这个假设。
Item 30: Familiarize yourself with perfect forwarding failure cases
参考
1、Scott Meyers
Effective Modern C++ : 42 Specific Ways to Improve Your Use of C++11 and C++14