Effective Modern C++: 右值引用

一:C语言中的右值概念

 

左值:既能出现在等号左边,又能出现在等号右边的变量(或表达式),可以寻址

右值:智能出现在等号右边的变量或表达式,无法寻址

例如:a = 10, a是左值,10就是右值

 

二:右值引用 rValue reference

C++11中用&&代表右值引用,左值引用只能引用左值,右值引用只能引用右值。

const T& 这个比较特殊,既能绑定左值,也能绑定右值 

 

示例代码:

 1 class A{
 2 public:
 3     int a;
 4     A(){}
 5 };
 6 
 7 A getTemp() {
 8     return A();
 9 }
10 
11 int main(){
12     A a;
13     A& refA = a;  //lValue
14     A&& refA2 = getTemp();    //rValue
15     const A& cRefA = a;    
16     const A& cRefA2 = getTemp();
17 
18     refA2 = std::move(refA);
19     return 0;
20 }

 

三:std::move

  • move函数的参数T&&是一个指向模板类型参数的右值引用【规则2】,通过引用折叠,此参数可以和任何类型的实参匹配,因此move既可以传递一个左值,也可以传递一个右值;

  在C++14中std::move模板方法的定义;

1 template<typename T>                          // C++14; still in
2 decltype(auto) move(T&& param)                // namespace std
3 {
4   using ReturnType = remove_reference_t<T>&&;
5   return static_cast<ReturnType>(param);
6 }
7 
8 摘录来自: “Effective Modern C++。” Apple Books. 

 

四:std::forward

  • std::forward实现了参数在传递过程中保持其值属性的功能,即若是左值,则传递之后仍然是左值,若是右值,则传递之后仍然是右值。
  • std::move 和 std::forward的差别:
  1. std::move执行到右值的无条件转换。就其本身而言,它没有move任何东西。
  2. std::forward只有在它的参数绑定到一个右值上的时候,它才转换它的参数到一个右值。
  3. std::move和std::forward只不过就是执行类型转换的两个函数;std::move没有move任何东西,std::forward没有转发任何东西。在运行期,它们没有做任何事情。它们没有产生需要执行的代码,一byte都没有。
  4. std::forward<T>()不仅可以保持左值或者右值不变,同时还可以保持const、Lreference、Rreference、validate等属性不变;
  • 示例:
 1 class Widget{};
 2 
 3 void processWidget(const Widget& w){
 4     std::cout<< "Process lValue"<<std::endl;
 5 }
 6 
 7 void processWidget(Widget&& w){
 8     std::cout<<"Process rValue"<<std::endl;
 9 }
10 
11 template<typename T>
12 void logAndProcess(T&& param){
13     processWidget(param);
14 }
15 
16 int main(){
17     Widget w;
18     logAndProcess(w);
19     logAndProcess(std::move(w));
20 }

上述代码输出并不是所预期的lValue和rValue,需要std::forward()对传入参数进行完美转发。

 1 class Widget{};
 2 
 3 void processWidget(const Widget& w){
 4     std::cout<< "Process lValue"<<std::endl;
 5 }
 6 
 7 void processWidget(Widget&& w){
 8     std::cout<<"Process rValue"<<std::endl;
 9 }
10 
11 template<typename T>
12 void logAndProcess(T&& param){
13     processWidget(std::forward<T>(param));
14 }
15 
16 int main(){
17     Widget w;
18     logAndProcess(w);
19     logAndProcess(std::move(w));
20 }

 

 



 

posted @ 2020-03-21 16:19  Asp1rant  阅读(193)  评论(0)    收藏  举报