2012-01-14 47 views
1

雖然試圖通過「傳值」和隨後的破壞與拷貝構造做實驗,我想這樣的代碼:實驗拷貝構造一個向量

#include <iostream> 
#include <string> 
#include <vector> 

using namespace std; 

class Rock{ 
int sz; 
public: 
Rock():sz(0){cout<< "Default ctor"<<endl;} 
~Rock(){cout<< "Dtor"<<endl;} 
Rock(const Rock& r){ cout << "Copy ctor" << endl; sz = r.sz;} 
Rock& operator=(const Rock& r) {cout << "In assignment op" << endl; sz = r.sz;} 
}; 

int main() 
{ 
vector<Rock> rocks; 
Rock a, b, c; 
rocks.push_back(a); 
rocks.push_back(b); 
rocks.push_back(c); 
return 0; 
} 

,並得到了以下的輸出。直到第7行一切都很好,但我無法理解從那時起會發生什麼。有人可以澄清嗎?

Default ctor 
Default ctor 
Default ctor 
Copy ctor 
Copy ctor 
Copy ctor // all fine I got it... 
Dtor 
Copy ctor 
Copy ctor 
Copy ctor 
Dtor 
Dtor 
Dtor 
Dtor 
Dtor 
Dtor 
Dtor 
Dtor 
+0

這是一個非常具有誤導性的輸出語句:'Rock&operator =(const Rock&r){cout <<「Copy ctor」<< endl; sz = r.sz;}'你應該考慮改變它,特別是當你的實際拷貝構造函數輸出完全相同的信息。 – 2012-01-14 14:19:57

+0

確實,複製粘貼錯誤...應該是分配操作員相關;-) Thx – 2012-01-14 14:21:45

+0

說'rocks.reserve(10);'在開始時比較。 – 2012-01-14 14:55:38

回答

3

讓我們將輸出關聯到相應的代碼行。

Rock a, b, c; 

Default ctor 
Default ctor 
Default ctor 

這一個你可能想出你自己。 :-)

rocks.push_back(a); 

Copy ctor 

再次,你可能已經正確地計算出了。

rocks.push_back(b); 

Copy ctor 
Copy ctor // all fine I got it... 
Dtor 

您的評論顯然是錯誤的,因爲你幾乎肯定沒有副構造都與這一說法:-)

什麼情況是,加入a副本的時候,矢量只分配調用足夠的內存來存儲a的一個副本(儘管允許允許分配更多)。因此,必須分配內存塊大到足以容納的ab兩個拷貝,複製a它存儲在到新一箇舊的內存塊中的複製,之後將其複製b,然後摧毀在釋放(現在不再需要的)原始內存塊之前的原始副本a

rocks.push_back(c); 

Copy ctor 
Copy ctor 
Copy ctor 
Dtor 
Dtor 

從上面的解釋,你現在應該能夠猜到這裏發生了什麼。

但是請注意,如果您將另一個元素推回到該向量中,很可能再次只獲得一個副本構造函數而不會析構函數調用。這是因爲向量的典型策略是在每一步中將分配的內存加倍,因此當推回c時,它最可能爲4個對象分配空間。實際上,std::vector需要使用指數策略(但不要求使用因子2,但有人認爲中值是一個更好的因子)。

} 

Dtor 
Dtor 
Dtor 
Dtor 
Dtor 
Dtor 

在這裏,三個對象cba,然後在載體中的三個對象被破壞。

1

每當std::vector有增長的能力(因爲你推更多的元素),它需要分配新的存儲,從舊的存儲到新的存儲複製所有已經存在的元素,然後刪除舊的元素。因此,你會得到複製構造函數和析構函數的「額外」調用。

如果您在的每個呼叫之間插入cout聲明,它應該有助於說明哪個呼叫/呼叫與每個呼叫push_back相關聯。

但是,這是我在年表猜測:

Default ctor 
Default ctor 
Default ctor 

// First push_back() (capacity initially 1) 
Copy ctor // Copy a into vector 

// Second push_back() (capacity now grows to 2) 
Copy ctor // Copy rocks[0] to new storage 
Copy ctor // Copy b into vector 
Dtor   // Destruct rocks[0] in old storage 

// Third push_back() (capacity now grows to 4) 
Copy ctor // Copy rocks[0] to new storage 
Copy ctor // Copy rocks[1] to new storage 
Copy ctor // Copy c into vector 
Dtor   // Destruct rocks[0] in old storage 
Dtor   // Destruct rocks[1] in old storage 

// End of main 
Dtor   // Destruct rocks[0] 
Dtor   // Destruct rocks[1] 
Dtor   // Destruct rocks[2] 
Dtor   // Destruct c 
Dtor   // Destruct b 
Dtor   // Destruct a 
+0

實際上,我忘記了vector_back在push_back調用期間必須改變其容量 – 2012-01-14 14:13:53

+0

您對最終析構函數的註釋是錯誤的:自動變量是以相反的構造順序被破壞的,因此首先是'c',然後是'b',然後' a'被破壞(然後是向量中的對象)。 – celtschk 2012-01-14 14:25:45

1

可以很容易地修改代碼以輸出更多信息:

#include <iostream> 
#include <string> 
#include <vector> 

using namespace std; 

class Rock{ 
    int sz; 
public: 
    Rock():sz(0){cout<< "Default ctor"<<endl;} 
    Rock(int x):sz(x){cout<< "int ctor " << x <<endl;} 
    ~Rock(){cout<< "Dtor " << sz <<endl;} 
    Rock(const Rock& r){ cout << "Copy ctor from " << r.sz << endl; sz = r.sz;} 
    Rock& operator=(const Rock& r) {cout << "Copy ctor " << sz << " from " << r.sz << endl; sz = r.sz;} 
}; 

int main() 
{ 
    vector<Rock> rocks; 
    Rock a(1), b(2), c(3); 
    rocks.push_back(a); 
    rocks.push_back(b); 
    rocks.push_back(c); 
    return 0; 
} 

它打印(使用說明):

int ctor 1 
int ctor 2 
int ctor 3 
Copy ctor from 1 // copies a into the vector 
        // push_back(a) returns (capacity == 1) 
Copy ctor from 1 // vector reallocates to a greater storage 
Copy ctor from 2 // copies b into the vector 
Dtor 1   // destroy the old elements 
        // push_back(b) returns (capacity == 2) 
Copy ctor from 1 // vector reallocates to a greater storage 
Copy ctor from 2 
Copy ctor from 3 // copy c into the vector 
Dtor 1   // destroy the old elements 
Dtor 2 
        // push_back(c) returns (capacity == 4) 
Dtor 3   // destroy the local a, b, c 
Dtor 2 
Dtor 1 
Dtor 1   // destroy the vector and its elements 
Dtor 2 
Dtor 3