C++ 11 move constructor 什麼時候調用?

C++11支持移動語義。ios

一:爲何須要移動語義和什麼是移動語義函數

咱們先來看看C++11以前的複製過程。假設有下列代碼:優化

vector<string> v1(1000000);//v1存放着100W個string,假設每一個string長度爲1000spa

vector<string> v2(v1);//使用v1初始化v2.net

vector和string類都使用動態內存分配,所以他們必須定義使用他們本身的new版本的複製構造函數。code

複製構造函數vector<string>將使用new給1000W個string分配對象,而每一個string 將使用new給每一個string分配1000個字符的空間大小。接下來所有的都將從v1中逐個複製string到v2中,這裏的工做量很是大,可是並無問題。orm

但真的沒有問題嗎?有時候答案是否認的。例如,假設有一個函數,他返回一個vector<string>對象。對象

vector<string>copyVector(const vector<string> &v){blog

vector<string> temp;ip

//複製100W個string到temp

return temp;

}

接下來,以如下方式調用這個函數。

vector<string> v1(1000000);//v1存放着100W個string,假設每一個string長度爲1000

vector<string> v2=copyVector(v1);//使用v1初始化v2

構造v2的時候,編譯器先利用v1構造生成了一個temp副本,而後將temp複製給一個臨時對象,返回給v2,v2利用該臨時對象,構造本身。

這將致使很是巨大的工做量!作了大量的無用功(將temp複製給一個臨時對象,返回給v2,v2利用該臨時對象,構造本身)。在這以後,temp這個臨時的對象被刪除了,返回的那個temp副本臨時對象也被刪除了,若是編譯器可以將temp的全部權直接轉移給v2不是更好嗎?也就是說,不用將100W個string屢次複製到新的地方,再刪除原來的字符,而是直接保留字符,並將v2與之關聯。這相似於計算機中文件的移動。實際文件還保留在原來的地方,而只是記錄修改了,這種方法稱之爲移動語義

移動語義避免了移動原始數據,而只是修改了記錄。

要實現移動語義,必須讓編譯器知道何時須要複製,何時不須要複製。這就是右值引用發揮最大做用的地方


二:如何實現移動語義

看一個簡單的使用移動語義的例子。

 1 #include <iostream>
 2  using  namespace std;
 3  class A{
 4      private:
 5          int data; // data
 6           int *pi; // point to data
 7       public:  
 8          // 禁止隱式轉換
 9          A(){
10         }
11          explicit A( int i):data(i){
12             cout<< " normal constuctor! "<<endl;
13             pi=&data;
14         }
15         A( const A &a){
16             data=a.data;
17             cout<< " copy constructor! "<<endl;
18             pi=&data;
19         }
20 
21         A(A &&a){
22             cout<< " move constructor! "<<endl;
23              // 直接移動a.pi到pi
24              pi=a.pi;
25              data = a.data;  // 修改源pi
26              a.pi=nullptr;
27             a.data= 0;
28         }
29          // A(A &&a)=delete;
30          A  operator+( const A &a){
31             A temp(data+a.data);
32             cout<<endl<< " operator+ called!show temp! "<<endl;
33             temp.show();
34             cout<<endl;
35              return temp;
36         }
37          void show() const{
38             cout<< " pi= "<<pi<< "    data= "<<data<<endl;
39         }
40 };
41 
42  int main()
43 {
44      int i= 99;
45     A a( 10);
46     a.show();
47     A b(i);
48     b.show();
49     A c(b);
50     c.show();
51     A d(b+c);
52     cout<< " show d! "<<endl;
53     d.show();
54 
55 

56 } 

 

 

 

 

運行截圖:

 

在CODE上查看代碼片

看出來什麼問題沒有?

對,好像並無調用移動構造函數!

可是有沒有發現!temp和d的pi都是指向同一個地方那個?這是什麼狀況?

原來是由於GCC自帶的右值語義!

也就是,編譯器GCC會幫你自動優化!

那麼微軟的編譯器呢? 

 

也會優化! 

 

不信請看下面例子!咱們利用C++11的delete特性!

#include <iostream>  
using  namespace std;  
class A{  
private:  
     int data; // data  
     int *pi; // point to data  
public:  
     // 禁止隱式轉換  
    A(){  
    }  
     explicit A( int i):data(i){  
        cout<< " normal constuctor1! "<<endl;    
        pi=&data;  
    }  
    A( const A &a){  
        data=a.data;  
        cout<< " copy constructor! "<<endl;  
        pi=&data;  
    }  
     /*  
    A(A &&a){ 
        cout<<"move constructor!"<<endl; 
        //直接移動a.pi到pi 
        pi=a.pi; 
        data = a.data;

        //修改源pi 
        a.pi=nullptr; 
        a.data=0; 

    }*/  
    A(A &&a)=delete;  
    A operator+(const A &a){  
        A temp(data+a.data);  
        cout<<endl<<"operator+ called!show temp!"<<endl;  
        temp.show();  
        cout<<endl;  
        return temp;  
    }  
    void show()const{  
        cout<<"pi="<<pi<<"   data="<<data<<endl;  
    }  
};  
int main(){  
    int i=99;  
    A a(10);  
    a.show();  
    A b(i);  
    b.show();  
    A c(b);  
    c.show();  
    A d(b+c);  
    cout<<"show d!"<<endl;  
    d.show();  
      
      
}  

 

運行結果:


也就是說,在return temp;這一句上將要調用A(A&&)這個構造函數;

可是如今這個函數被咱們顯式刪除了!

b+c也是一個右值!也是須要調用移動構造函數的!

所以上一個例子其實是調用了移動語義的構造函數!

 

那麼vs2013呢?有intelisense,你根本沒法編譯!!

 

 

=================================================================================

相關文章
相關標籤/搜索