c++ 11的右值引用的具体使用

  

c++ 11引入了std::移动语义,右值引用,移动构造和完美转发这些特性。由于这部分篇幅比较长,分为3篇来进行阐述。

  

在了解这些特性之前,我们先来引入一些问题。

  


  

  
      <李>函数返回值是传值的时候发生几次对象构造,几次拷贝?李   <李>函数的形参是值传递的时候发生几次对象构造?李   
  

让我们先来看一段代码,

     //main.cpp   # include & lt; iostream>   使用名称空间性病;      A类{   公众:   () {   cout<& lt;“A类构造!”& lt; & lt; endl;   }   (const第一部;){   cout<& lt;“类副本!”& lt; & lt; endl;   }   第一部;操作符=(const第一部;){   cout<& lt;“任务称为!”& lt; & lt; endl;   }   ~ (){   cout<& lt;“A类破坏!”& lt; & lt; endl;   }   };      get_A_value () {   返回一个();   }   int main () {   一个=get_A_value ();   返回0;   }      之前      

使用g++编译;注意使用-fno-elide-constructors关闭省略构造优化

        g++主要。cpp -fno-elide-constructors      

可以得到以下输出

  
  

类构造!
  类自毁!
  类一本!
  类自毁!
  类自毁!
  

     

可以看到一个=get_A_value ();一行代码居然产生1次对象构造和2次对象的拷贝构造!具体为

  
      <李>在get_A_value()里()构造了临时对象,发生了一次构造;李   <李>函数返回的时候会把临时对象拷贝后作为返回值,发生一次拷贝;李   <李>一个=函数返回值发生了拷贝构造。   
  

如果使用编译器优化(默认),则会把临时对象拷贝的那次和用返回值构造最终对象的拷贝的给省略了;也即,只有一次拷贝和析构。

  
  

类构造!
  类自毁!
  

     

如果把上面代码改一下

     //桓?      空白pass_A_by_value(一){      }   int main () {   一个一个;   pass_A_by_value(一个);   返回0;   }      之前      

在去掉优化g++主要。cpp -fno-elide-constructors时输出为

  
  

类构造!
  类一本!
  类自毁!
  类自毁!
  

     

1次构造加上1次拷贝。

  

因此,下次如果面试的时候有人问这个问题,你就可以说:默认情况下经过编译器优化后临时对象的拷贝就会被省去,如果使用-fno-elide-constructors省略优化,则还要考虑临时对象的拷贝。

  

事实上,在未经优化的情况下,以下时候拷贝构造函数会被调用:

  
      <李>函数内的局部对象做为返回值返回(不是引用)的时候会发生拷贝(拷贝为临时对象返回)   <李>函数形参为传值的时候,会发生拷贝构造李   <李>一个对象以另外一个对象进行初始化的时候李   
  

对象的频繁构造是程序的开销,特别是当对象内部有堆上内存(比如有新出来的成员)的时候,每次拷贝构造的时候都需要用新申请一块内存,造成性能的降低。对于情况2,好习惯是如果函数参数是只读的(也即不会在程序内进行修改),传引用作为参数,也即pass_A_by_refrence (const,一个);对于情况1,编译器会为我们进行优化;对于情况3,c++ 11引入了一种移动构造函数的概念,它将获取* *右值引用*,右值的“资源”移动到新对象中,这个过程中不会申请新的内存,从而达到提高了效率和性能。

  

所以,要理解些关键词“移动构造”、“移动语义”,首先要理解右值和右值引用。

  


  

  

<强> 2.1左值(左值和右值(右值)
  

  

在一,问题导入里我们提到了临时对象,也即函数返回值的时候只会“临时“存在的对象(运行超过那一行就会结束它的生存期),这个临时返回值就是一个右值;
  右值的最直观的定义为,顾名思义:

  

位于赋值运算符=右边的值,为右值;在左边的则为左值

  如

        一个=foo ();//foo()为右值   char * x=扒寤?//扒寤蔽置嬷狄参抑?   a=b + c;//b + c这个结果也是一个右值   之前      

在c++中,还有个定义为:

  

左值可以取得地址,有名字;不可以取得地址,没有名字的为右值。

c++ 11的右值引用的具体使用