C++-copy constructor、copy-assignment operator、destructor

本文由@呆代待殆原創,轉載請註明出處。程序員

 

對於一個類來講,咱們把copy constructor、copy-assignment operator、move constructor、move-assignment operator、destructor統稱爲copy control。數組

今天咱們先來聊聊其中的copy constructor、copy-assignment operator的destructor這三個。函數

 

copy constructor優化

copy constructor:一個constructor若是他的第一個參數是對類的引用,且其餘的參數都有缺省值(default values)則,這是一個copy constructor。spa

1,第一個參數必須是引用類型,由於當咱們把一個object當作參數傳遞給一個方法的非引用變量的時候會自動調用copy constructor方法,若是copy constructor自身的參數就是非引用類型的話,這個方法就會引發無限遞歸調用,而後你的程序就boomshakalaka~~。指針

2,通常咱們會把第一個參數設成const,由於通常狀況下不會對其進行修改,除非你另有打算。code

3,由於copy constructor在不少狀況下是默認調用的,如如下狀況,因此通常不會把copy constructor設成explicit。blog

1 std::string s;
2 std::string s1 = s; //隱式調用了copy constructor
3 std::string s2 = std::string(s1);//顯式調用了copy constructor

 

1 class Foo{
2 public:
3     Foo(const Foo&);
4     //...
5 };

什麼時候發生copy constructor調用遞歸

爲了弄清這個問題咱們須要弄清另一組概念:direct initialization 和copy initialization。內存

direct initialization:要求編譯器按照通常的方法匹配(function matching)來選擇要調用的方法。

copy initialization:要求編譯器將右操做數拷貝到左操做數,有必要的話還會進行類型轉換,這個過程會調用copy constructor或者move constructor(本文暫不介紹)。

1 std::string s1("balabala");                       //direct initialization
2 std::string s2(10, 'a');                          //direct initialization
3 std::string s3 = s2;                              //copy initialization
4 std::string s4 = std::string(s3);                 //copy initialization
5 std::string s5 = "const char* converts to string";//copy initialization

 copy initialization發生的狀況以下:

1,用=來初始化定義的變量時。

2,把一個object當作參數傳遞給一個方法的非引用變量的時。

3,方法返回一個非引用類型的object時。(返回時會首先生成一個臨時object)

4,用花括號列表初始化一個數組或聚合類(aggregate class)成員時。

因爲編譯器帶來的誤解:

如今的編譯器有時候會自動繞過copy constructor即編譯器會把下面這一句話

 std::Book book = "9-9-9-9";//假設Book是一個自定義的類 

換成下面這個

 std::Book book("9-9-9-9"); 

請注意在執行上上面兩句語言是徹底不同的,第一句會首先調用Book(const char*)構造函數生成一個臨時object而後再調用Book(const Book&)把臨時object複製給book。而第二句話會直接調用Book(const char*)而後完事兒。若是你想驗證他們的區別能夠實現Book類並將Book(const Book&)設置成私有方法(防止編譯器自動優化),以後你就會發現第一條語句沒法執行了。

 

Copy-assignment operator

copy-assignment operator:寫這個方法就是對=操做符進行重載。

1,copy-assignment operator的返回值通常是對其左操做數(left-hand operand)的引用,這是爲了讓object的行爲更像內置類型而決定的。

1 class Foo{
2 public:
3     Foo& operator=(const Foo&);
4     //...
5 };

什麼時候發生copy-assignment operator調用

答案很顯然是用到=操做符的時候啊,可是這裏要注意的是

初始化的時候並不會調用copy-assignment operator

初始化的時候並不會調用copy-assignment operator

初始化的時候並不會調用copy-assignment operator

重要的事情說三遍,舉例以下

1 std::string s;
2 std::string s1 = s;    //對s1進行初始化,調用的是copy constructor
3 s1 = s;                //對s1進行賦值,調用的是copy-assignment operator

 

 Destructor

Destructor:destructor有兩個部分,function body和destruction part,前者由類的編寫者寫明須要作的內容,後者是隱式的,不須要程序員關心,在function body執行完後自動執行,會銷燬類的非靜態數據成員。

1,由於Destructor沒有參數,因此它是不能被重載的

1 class Foo{
2 public:
3     ~Foo();
4     //...
5 };

什麼時候發生Destructor調用

1,當超出object 的做用域(scope)時。

2,容器銷燬時(container),裏面的元素(element)也會跟着調用自身的destructor從而銷燬。

3,人爲使用delete的時候。

4,由某個表達式建立的臨時變量在這個表達式執行完後將自動調用destructor從而銷燬。

5,類的成員若是自身有destructor,會在這個類銷燬的時候調用自身的destructor。

 

 關於編譯器自動提供的版本(Synthesized)

Synthesized copy constructor:即便咱們提供了其餘版本的copy constructor,編譯器仍然會提供這個版本的copy constructor給咱們,它會依次複製非靜態成員給被建立的object,對數組也能正常工做,對於class類型會調用它們本身的copy constructor。

Synthesized copy-assignment operator:行爲和Synthesized copy constructor相似,依次把非靜態成員複製給左操做數。

Synthesized destructor:destructor的function body爲空。

 

 關於什麼時候咱們須要自定義上述的三個方法

1,當須要destructor時,上述三給方法都是須要的。

2,當須要copy constructor時,copy-assignment operator也是須要的,反之亦然。

而當咱們須要刪除本身動態分配的內存時,就要用到destructor。

當咱們須要進行深度複製時會用到另外兩個,好比對指針指向的元素進行復制等等。

 

關於delete和default的用法

咱們能夠用default顯示聲明咱們想要用默認版本的copy control,也能夠用delete顯示聲明咱們徹底不須要這類方法來達到禁止這個object進行相關的複製和賦值操做。

1,咱們能delete除了destructor之外的全部方法來達到顯示告知這個object不能進行相關操做的目的,delete只能寫在一次聲明出現的地方。

2,咱們能對全部有默認版本的函數用default顯示聲明咱們須要這個默認版本,default能夠寫在方法聲明的地方也能夠寫在方法定義的地方。

1 class Foo{
2 public:
3     Foo() = default;                     //顯式說明使用默認版本
4     Foo(const Foo&) = delete;            //delete copy constructor
5     Foo& operator=(const Foo&) = delete; //delete copy-assignment operator
6     ~Foo() = default;                    //顯式說明使用默認版本
7     void myFuntion() = delete;           //delete本身的方法
8     //...
9 };

 

 

參考資料:《C++ primer 英文第五版》

相關文章
相關標籤/搜索