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

C++构造函数处理临时对象异常:两种结构体构造结果差异咨询

为什么两段C++代码的移动构造结果不同?

测试代码定义

#include <iostream>
using namespace std;

struct Test
{
    int size;
    Test(int a) { cout << "default" << endl; size = a; }
    Test(Test const & t) { cout << "copy" << endl; size = t.size + 1; }
    Test(Test && t) { cout << "move" << endl; size = t.size + 1; }
    ~Test() { cout << "destruct" << endl; }
};

struct Test2
{
    int size;
    Test2(int a) { cout << "default2" << endl; size = a; }
    Test2(Test const & t) { cout << "copy2" << endl; size = t.size + 1; }
    Test2(Test && t) { cout << "move2" << endl; size = t.size + 1; }
    ~Test2() { cout << "destruct2" << endl; }
};

测试场景1

int main() {
    Test t{3};                                       // 输出"default"
    cout << t.size << endl;                          // 输出3
    Test move_from_temp = Test(Test(std::move(t)));  // 输出"move"
    cout << move_from_temp.size << endl;             // 输出4
    return 0;
}

测试场景2

int main() {
    Test t{3};                                         // 输出"default"
    cout << t.size << endl;                            // 输出3
    Test2 move_from_temp = Test2(Test(std::move(t)));  // 依次输出"move"、"move2"、"destruct"
    cout << move_from_temp.size << endl;               // 输出5
    return 0;
}

问题描述

预期上述两个场景的结果应该一致,但实际输出不同,请问造成差异的原因是什么?

原因分析

核心差异来自C++复制消除(Copy Elision)机制的应用限制:

  • 场景1:触发复制消除
    语句Test move_from_temp = Test(Test(std::move(t)));中,所有临时对象的类型都是Test。根据C++标准的复制消除规则(尤其是返回值优化RVO的扩展场景),编译器可以直接将最内层临时对象的构造结果直接初始化move_from_temp,跳过中间的移动构造步骤。实际执行流程简化为:

    1. std::move(t)将t转为右值,触发Test(Test&&)构造函数,直接初始化move_from_temp,size变为3+1=4;
    2. 完全跳过外层的Test(...)临时对象构造,因此只触发一次移动构造,最终move_from_temp.size为4。
  • 场景2:无法触发复制消除
    语句Test2 move_from_temp = Test2(Test(std::move(t)));中,内层临时对象是Test类型,外层构造的是Test2类型——两者类型不匹配,编译器无法进行复制消除,必须完整执行所有构造步骤:

    1. Test(std::move(t))触发Test(Test&&),构造出size=4的Test临时对象,输出"move";
    2. 用这个Test右值临时对象触发Test2(Test&&)构造函数,构造move_from_temp,size变为4+1=5,输出"move2";
    3. 临时Test对象被析构,输出"destruct";
      最终move_from_temp.size为5。

补充:复制消除是C++标准允许的优化,即使会改变构造/析构函数的调用次数(进而改变输出),编译器也有权执行。只有当临时对象和目标对象类型一致时,才有可能触发这类对象构造的合并优化。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 10:15:33