2

我有以下代码

#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;调用复制构造函数并Copy-construct(1)在打印( b ).

同样在复制构造函数的打印( c )再次被调用两次之后?,我不确定这个函数是如何产生的 Object func(Object var) { return var; }

并且在 打印Destruct(1)之前被调用两次。( d )

抱歉,这个问题很长,我对上述内容感到困惑。

4

3 回答 3

5
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)从堆栈中弹出,并为每个变量调用析构函数。

于 2010-06-06T07:33:22.973 回答
2

我对此有一些问题,首先为什么 Object v4 = v1; 在打印 ( b ) 之后调用复制构造函数并生成 Copy-construct(1)。

尽管有=符号,但您在此处调用复制构造函数。请记住,您没有默认构造函数。您正在构建一个新的Object并使用 的值对其进行初始化v1。你要这样做:

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

……你会看到……

( b )
Construct(0)
0 = 1

......我认为你正在期待。

同样在打印( c )之后,复制构造函数又被调用了两次?,我不确定这个函数是如何产生那个 Object func(Object var) { return var; }

在这里,您var通过值传递(而不是通过引用 [&]),这意味着创建了对象的副本(对复制构造函数的一次调用)。然后您返回另一个对象(再次,而不是引用),因此必须制作另一个副本(对复制构造函数的第二次调用)。

并且在打印 ( d ) 之前调用 Destruct(1) 两次。

您刚刚使用复制构造函数创建的那些对象?他们只是超出了范围,他们的析构函数被调用了。

当你delete v5调用它的析构函数时。

然后你到达你的main函数的末尾,你在堆栈上创建的三个Object实例 ( v1, v2, v4) 到达它们的生命周期的尽头,并在堆栈展开时被销毁。

您可能已经注意到,您的析构函数调用与构造函数调用的数量完全相同!

于 2010-06-06T07:21:27.280 回答
1

至于第一个问题,Object v4 = v1;是语法糖Object v4(v1);,它更明显地调用了复制构造函数。

第二个有点复杂。当按值将变量传递给函数时,它们必须被复制 - 因此调用复制构造函数。对象的副本也必须放在堆栈中调用者可以访问它的位置,因为传递给函数的副本在函数返回时不复存在。在完成这两个副本之后,参数在从堆栈中弹出时被破坏,并且返回值被破坏,因为它的值没有被使用。它们具有相同的 ID,因为它们是v1.

于 2010-06-06T07:08:18.497 回答