假设我有一个学生类的方法:
Student Student::method(Student x)
{
//nothing important
return x;
}
复制构造函数被调用两次,一次是当对象 x 作为参数发送时,第二次是从函数返回 x 时。
当我调用此方法时,为什么以及何时调用了两次 Student 类的析构函数?调用是这样的:a = b.method(c),其中 a、b 和 c 是 Student 对象。
假设我有一个学生类的方法:
Student Student::method(Student x)
{
//nothing important
return x;
}
复制构造函数被调用两次,一次是当对象 x 作为参数发送时,第二次是从函数返回 x 时。
当我调用此方法时,为什么以及何时调用了两次 Student 类的析构函数?调用是这样的:a = b.method(c),其中 a、b 和 c 是 Student 对象。
对于您的示例,a = b.method(c);
可能会发生三个副本,除了复制省略。第一个是当c
对象被复制到函数参数中时x
。第二个是x
从函数返回对象时。第三个是返回值被复制到a
对象中的时候。前两个涉及复制构造函数,最后一个涉及复制赋值运算符,除非您将其更改为Student a = b.method(c);
,在这种情况下它们都使用复制构造函数。
a
, b
, 并且c
都将在其作用域结束时被销毁。该对象x
将在method
函数结束时被销毁。函数的返回值将在包含它的完整表达式的末尾被销毁——也就是说,一旦a = b.method(c);
完成。
但是,并非所有这些副本都必须发生 - 允许编译器在某些情况下省略或省略类的复制/移动构造。将发生第一次复制到函数参数中。函数的第二个副本将被视为先移动,然后再尝试复制它。此复制或移动可能会被省略。a
如果您使用复制赋值,则从临时返回值到 的最终复制将发生,但如果您使用复制构造函数(如Student a = b.method(c);
),则可能会被省略。
如果构造了两个 Student 对象,则必须将它们销毁。传入参数和传出返回值的副本需要破坏。
x
当函数返回时调用析构函数(在x
被复制到返回值之后)。
返回值的析构函数在包含函数调用的完整表达式的末尾调用(除非返回值通过分配给引用来延长其生命周期)。
每个被构建的具有自动存储持续时间的对象都会被自动销毁(通常以相反的构建顺序)。您构造了两个对象(x
和返回值),因此有两个析构函数调用。