2015-10-09 104 views
2

我正在學習瞭解類構造函數和析構函數。 我已經寫了一個小控制檯代碼來添加一個類實例到一個向量中。所有的都很好,很花哨,但我不明白的是,向矢量中添加一個對象會觸發兩次析構函數。爲什麼會發生?Vector和push_back()行爲

如果我不添加任何對象,矢​​量不會自行觸發構造函數或析構函數,那麼它爲什麼會發生兩次?

任何人都可以解釋爲什麼會發生這種情況?

#include <cstdio> 
#include <vector> 
class Test 
{ 
    private: 
     int value; 

    public: 
     Test() 
     { 
      printf("\nClass constructor triggered."); 
     }; 
     ~Test() 
     { 
      printf("\nClass desctructor triggered."); 
     } 
}; 

int main() 
{ 
    std::vector<Test> container; 

    container.push_back(Test()); 
    return 0; 
} 

更新: 我增加了一些更多的信息類,使我得到更具體的輸出,但是現在我發現,每次除了矢量布展施工和析構函數調用增加。這些調用的數量是與矢量內的對象數量還是發生了什麼? 我有泄漏嗎?對不起,如果太愚蠢的問題。 下面是添加的代碼:

#include <cstdio> 
#include <vector> 

class Test 
{ 
    private: 
     int value; 

    public: 
     // Constructor 
     Test(int v=0) 
     { 
      value = v; 
      printf("\n\n%i", value); 
      printf("\nClass constructor triggered."); 
     }; 

     // Copy-move constructor 
     Test(Test&&) 
     { 
      printf("\nClass move-constructor triggered."); 
     }; 

     // Destructor 
     ~Test() 
     { 
      value = 0; 
      printf("\nClass desctructor triggered."); 
     } 
}; 

int main() 
{ 
    std::vector<Test> container; 

    container.push_back(Test(1)); 
    container.push_back(Test(2)); 
    container.push_back(Test(3)); 
    container.push_back(Test(4)); 

    printf("\n\nPushback complete!"); 
    return 0; 
} 
+0

因爲一個副本是與'push_back()'採取的。 –

+0

由於矢量包含對象,而不是指向它們的指針,因此將在插入時複製對象,然後有兩個對象要銷燬。 –

+2

@πάνταῥεῖ:答案去那裏↓↓↓↓↓我必須告訴你多少次 –

回答

3

因爲您不打印每個構造函數調用,所以在移動構造函數調用時錯過了。除了您提供的默認構造函數之外,您的類還隱式生成了移動和複製構造函數。

矢量存儲一個值,並且該值必須以某種方式進行初始化。典型地,這通過移動C-tor或複製C-tor發生,儘管也可以使用例如在矢量內直接創建對象emplace_back

嘗試添加此:

Live On Coliru

Test(Test&&) 
{ 
    printf("\nClass move constructor triggered."); 
}; 

你的課,應該改變輸出的東西更有意義(我也爲main末增加了打印)

Class constructor triggered. 
Class moveconstructor triggered. 
Class desctructor triggered. 
Out of main scope. 
Class desctructor triggered. 

第一析構函數調用破壞移動出「空」 Y的實例我們的班級,而第二個火災時矢量本身被摧毀。

5

你的矢量包含複製您通過push_back()添加到它的對象。第一個析構函數調用是由包含對push_back()的調用的完整表達式結尾處創建的臨時銷燬造成的。第二個析構函數是由向量本身被銷燬時向量中的副本被銷燬造成的。

您可以通過添加診斷,以main()說服自己:

int main() 
{ 
    std::vector<Test> container; 

    container.push_back(Test()); 

    printf("\nThis is before the vector is destroyed..."); 

    return 0; 
} 

可以在此live example觀察輸出。

通過爲您的類調用自動生成的移動構造函數(而不是使用默認構造)來創建您的矢量所包含的副本,這就是爲什麼您看不到相應的構造診斷。

如果你定義自己的移動構造函數(或拷貝構造函數,如下圖所示)發出的診斷,輸出將接近你所期望:

Test(Test const&) 
    { 
     printf("\nCopy construction triggered."); 
    }; 

再次,live example

2

爲簡單起見,我們假設您正在使用C++ 03,並且移動語義尚不可用。

添加拷貝構造函數地看到,它也引發

Test(const Test&) 
{ 
    printf("\nClass copy constructor triggered."); 
}; 

輸出

Class constructor triggered. 
Class copy constructor triggered. 
Class destructor triggered. 
Class destructor triggered. 

因此,有建造/銷燬兩個對象。

粗略地說,你的代碼是等於

int main() 
{ 
    std::vector<Test> container; 

    Test test;     // first object created 
    container.push_back(test); // second object created by copying 
    return 0; 
} 
+1

這真的不一樣,因爲他直接將臨時傳遞給push_back。由於它具有右值ref超載,因此可以使用移動構造函數。在你的情況下,因爲你定義了一個自定義的copy-ctor,所以不會生成隱式的move-ctor。 –

+0

@BartekBanachewicz你爲什麼認爲它是C++ 11? – Stas

+0

@Stas:本年度爲2015年。除非另有說明,否則我們假設非過時技術。 –

2

push_back()不會觸發任何析構函數(在這種情況下)。

兩個呼叫Test的析構函數是:

1 - 因爲你穿越到臨時到push_back(),使物體被摧毀時push_back()完成

2 - 當程序結束,所以vector被破壞,所以它的內容

相關問題