2010-06-06 139 views
1

我有以下代碼析構函數和拷貝構造函數調用。(爲什麼它被調用在這些時間)

#include <iostream> 
using namespace std; 

class Object { 

public: 
    Object(int id){ 
    cout << "Construct(" << id << ")" << endl; 
    m_id = id;  
    } 

    Object(const Object& obj){ 
     cout << "Copy-construct(" << obj.m_id << ")" << endl; 
     m_id = obj.m_id; 
    } 

    Object& operator=(const Object& obj){ 
     cout << m_id << " = " << obj.m_id << endl; 
     m_id = obj.m_id; 
     return *this; 
    } 

    ~Object(){ 
     cout << "Destruct(" << m_id << ")" << endl; 
    } 
private: 
    int m_id; 

}; 

Object func(Object var) { return var; } 

int main(){ 
    Object v1(1); 
    cout << "(a)" << endl; 
    Object v2(2); 
    v2 = v1; 
    cout << "(b)" << endl; 
    Object v4 = v1; 
    Object *pv5; 
    pv5 = &v1; 
    pv5 = new Object(5); 
    cout << "(c)" << endl; 
    func(v1); 
    cout << "(d)" << endl; 
    delete pv5; 
} 

其輸出

Construct(1) 
(a) 
Construct(2) 
2 = 1 
(b) 
Copy-construct(1) 
Construct(5) 
(c) 
Copy-construct(1) 
Copy-construct(1) 
Destruct(1) 
Destruct(1) 
(d) 
Destruct(5) 
Destruct(1) 
Destruct(1) 
Destruct(1) 

我有一些問題,爲此,首先爲什麼Object v4 = v1;在打印(b)後調用複製構造函數並生成Copy-construct(1)

而且之後的(c)打印拷貝構造函數被再次調用兩次?我不是一定的此功能的工作原理來產生 Object func(Object var) { return var; }

和只是Destruct(1)之後被調用(d)在打印之前的兩倍。

對於長期的問題感到抱歉,我很困惑以上。

回答

3
Object v1(1); 
// Construct(1) 

定期構造函數調用自動堆棧變量(在函數結尾處銷燬)。

cout << "(a)" << endl; 
// (a) 

Object v2(2); 
// Construct(2) 

另一個構造函數調用。

v2 = v1; 
// 2 = 1 

因爲V2已經創建賦值運算符是所謂的(我們稱爲構造函數的話),現在我們要指定一個現有的對象到另一個。

cout << "(b)" << endl; 
// (b) 

Object v4 = v1; 
// Copy-construct(1) 

複製構造函數在這裏被調用,因爲Object v4還沒有創建,所以我們創建它作爲v1的副本。分配在這裏是指的是一樣的,如果你沒有Object v4(v1)

Object *pv5; 
pv5 = &v1; 
pv5 = new Object(5); 
// Construct(5) 

調用構造函數的堆對象(delete明確破壞)。

cout << "(c)" << endl; 
// (c) 

func(v1); 
// Copy-construct(1) <br /> 
// Copy-construct(1) <br /> 
// Destruct(1) <br /> 
// Destruct(1) <br /> 

複製構造函數首先被調用以將v1複製到參數var。它被再次調用以創建var的副本作爲返回值給調用者。 var在退出函數時從堆棧彈出時被銷燬。在表達式func(v1)後,返回值被銷燬。

cout << "(d)" << endl; 
// (d) 

delete pv5; 
// Destruct(5) 

pv5指向的對象被手動銷燬。

} // end of main 
// Destruct(1) <br /> 
// Destruct(1) <br /> 
// Destruct(1) <br /> 

的自動變量V1,V2,V4(所有具有來自任一分配複製V1的id或複製結構)被彈出堆棧和析構函數被調用用於每個。

1

至於第一個問題,Object v4 = v1;Object v4(v1);的語法糖,它更明顯地調用了拷貝構造函數。

第二個有點複雜。當按值傳遞變量給函數時,它們必須被複制 - 從而調用拷貝構造函數。對象的副本也必須放置在調用方可以訪問的位置的堆棧上,因爲當函數返回時傳遞給該函數的副本不再存在。在完成這兩個副本之後,該參數在從堆棧彈出時被破壞,並且由於未使用該值而導致返回值被破壞。他們有相同的ID,因爲他們是v1的副本。

+0

ahk非常感謝。還有一個問題,'Destruct(1)'的最後3個輸出是由於Object v1(1),v2 = v1,Object v4 = v1;'correct?和'Destruct(5)'是在之前被人爲刪除的? – silent 2010-06-06 07:20:01

2

我有這個問題,首先是 爲什麼Object v4 = v1; (b)的打印 之後複製構造(1)調用副本 構造函數併產生 副本構造(1)。

儘管=符號,您在這裏調用複製構造函數。請記住,你沒有默認的構造函數。您正在構建新的Object並將其初始化爲值v1。是你做的事:

cout << "(b)" << endl; 
Object v4(0); 
v4 = v1; 

...你會看到...

(b) 
Construct(0) 
0 = 1 

...我想你期待。

而且(三) 拷貝構造函數又被稱爲印刷後 兩次?我不是一定這樣 功能如何運作,以產生對象 FUNC(對象VAR){VAR回報; }

在這裏,你是由值傳遞var(而不是通過引用[&]),這意味着該對象的副本被創建(一個呼叫到拷貝構造)。然後你返回另一個對象 (再次,而不是引用),所以必須做另一個副本(第二次調用複製構造函數)。

和只是自毀(1)得到 (d)在打印之前調用兩次之後。

那些剛剛使用複製構造函數創建的對象?他們只是超出了範圍,他們的析構函數被調用了。

當你deletev5它的析構函數被調用。

然後你到達main功能的結束和你堆棧(v1v2v4)上創建三個Object情況下達到其壽命結束和堆棧展開銷燬。

您可能已經注意到,您具有與構造函數調用一樣多的析構函數調用!

+0

你能解釋最後4個析構函數嗎? – silent 2010-06-06 07:27:53

+1

我已經更新了我的答案來解釋這些。 – Johnsyweb 2010-06-06 07:34:02

相關問題