析构函数和拷贝构造函数调用。(为什么它被调用在这些时间)

问题描述:

我有以下代码析构函数和拷贝构造函数调用。(为什么它被调用在这些时间)

#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)在打印之前的两倍。

对于长期的问题感到抱歉,我很困惑以上。

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或复制结构)被弹出堆栈和析构函数被调用用于每个。

至于第一个问题,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

我有这个问题,首先是 为什么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