You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何析构函数被错误对象调用?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吗?


原因解析

你混淆了对象赋值操作和对象创建/销毁的本质:

  1. 第一步Test t = Test(1);:
    这是拷贝初始化,编译器会触发返回值优化(RVO),直接在t的内存位置构造num=1的对象,所以输出第一行构造信息。此时t是一个存储num=1的对象,占据栈上的固定内存位置。

  2. 第二步t = Test(2);:

    • 首先构造一个临时Test对象(num=2),输出第二行构造信息;
    • 调用C++默认生成的赋值运算符,把临时对象的num值(2)赋值给t的num成员,此时t的num从1被修改为2,但t本身还是原来的那个对象,没有被销毁;
    • 临时对象的生命周期在赋值完成后立刻结束,所以调用它的析构函数,输出第三行Test destructed. Num = 2——这一步销毁的是那个临时的num=2对象,不是原来的t。
  3. 代码块结束时:
    t对象(此时num已经是2)的生命周期结束,调用它的析构函数,输出第四行Test destructed. Num = 2。

简单说:赋值操作不会销毁原来的对象,只是修改它的成员;第三行销毁的是临时创建的num=2对象,而原来的t对象直到作用域结束才销毁,此时它的num已经被改成2了。


内容的提问来源于stack exchange,提问作者RomanGirin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 05:17:17