为何析构函数被错误对象调用?C++对象生命周期疑问
C++对象赋值后析构输出不符合预期的原因解析
问题代码
class Test { public: Test(int num) { this->num = num; std::cout << "Test constructed. Num = " << num << std::endl; } Test(const Test& rhs) { num = rhs.num; std::cout << "Test copy constructed. Num = " << num << std::endl; } ~Test() { std::cout << "Test destructed. Num = " << num << std::endl; } int num; }; int main() { { Test t = Test(1); t = Test(2); } }
执行输出
Test constructed. Num = 1 Test constructed. Num = 2 Test destructed. Num = 2 <---- 预期此处Num为1 Test destructed. Num = 2
疑问
为何第三行输出中,析构函数被num字段为2的对象调用?难道不应该是num为1的对象的析构函数被调用吗?我们销毁num为1的对象,并让t变量存储num为2的对象,不是吗?
曾考虑过num为2的对象在栈顶,因此会先于num为1的对象被销毁,但抛开内部实现,毕竟是num为1的对象被销毁,那析构函数不该输出num=1吗?
原因解析
你混淆了对象赋值操作和对象创建/销毁的本质:
第一步
Test t = Test(1);:
这是拷贝初始化,编译器会触发返回值优化(RVO),直接在t的内存位置构造num=1的对象,所以输出第一行构造信息。此时t是一个存储num=1的对象,占据栈上的固定内存位置。第二步
t = Test(2);:- 首先构造一个临时Test对象(num=2),输出第二行构造信息;
- 调用C++默认生成的赋值运算符,把临时对象的
num值(2)赋值给t的num成员,此时t的num从1被修改为2,但t本身还是原来的那个对象,没有被销毁; - 临时对象的生命周期在赋值完成后立刻结束,所以调用它的析构函数,输出第三行
Test destructed. Num = 2——这一步销毁的是那个临时的num=2对象,不是原来的t。
代码块结束时:
t对象(此时num已经是2)的生命周期结束,调用它的析构函数,输出第四行Test destructed. Num = 2。
简单说:赋值操作不会销毁原来的对象,只是修改它的成员;第三行销毁的是临时创建的num=2对象,而原来的t对象直到作用域结束才销毁,此时它的num已经被改成2了。
内容的提问来源于stack exchange,提问作者RomanGirin
相关产品推荐
相关产品推荐

