我有以下代码
#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 )
之前被调用两次。
答案 0 :(得分:4)
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 :(得分:2)
首先,我有一些问题 为什么Object v4 = v1;打电话给副本 构造函数和生产 打印后复制构造(1) (b)。
尽管有=
符号,但您在这里调用了复制构造函数。请记住,您没有默认构造函数。您正在构建新的Object
并使用v1
的值对其进行初始化。你做的是:
cout << "( b )" << endl;
Object v4(0);
v4 = v1;
......你会看到......
( b )
Construct(0)
0 = 1
...我认为你在期待。
在(c)印刷之后 再次调用copy-constructor 两次?,我不确定这是怎么回事 函数用于生成该对象 func(Object var){return var; }
在这里,您通过值(而不是引用[&amp;])传递var
,这意味着创建了对象的副本(对复制构造函数的一次调用)。然后你返回另一个对象
(再次,而不是引用)所以必须进行另一个副本(第二次调用复制构造函数)。
就在Destruct(1)之后 在打印之前调用两次(d)。
您刚刚使用复制构造函数创建的那些对象?他们刚刚超出范围,他们的析构函数被调用。
当你delete
v5
调用它的析构函数时。
然后,您到达main
函数的末尾以及您在堆栈上创建的三个Object
实例(v1
,v2
,v4
)到达它们的生命周期结束并在堆栈解开时被破坏。
您可能已经注意到,您拥有与构造函数调用一样多的析构函数调用!
答案 2 :(得分:1)
关于第一个问题,Object v4 = v1;
是Object v4(v1);
的语法糖,更明显地调用了复制构造函数。
第二个有点复杂。当按值传递变量到函数时,必须复制它们 - 因此调用复制构造函数。对象的副本也必须放在堆栈中调用者可以访问它的位置,因为传递给函数的副本在函数返回时不再存在。在完成这两个副本之后,参数在从堆栈弹出时被破坏,并且返回值被破坏,因为它的值没有被使用。它们具有相同的ID,因为它们是v1
的副本。