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

为何X x(X{});仅调用默认构造而非默认+移动构造?

问题分析与解释

代码示例

class X {
public:
    X(int x):m_x(new int{x}) {
        cout << this << '\t';
        cout << "Constuctor X(int x)"<<endl;

    } 
    X() {
        cout << this << '\t';
        cout << "Constuctor X()"<<endl;
    }
    X(const X& x) {
        cout << this << '\t';
        cout << "Constuctor X(const X&)"<<endl;
        cout << "addr of const X& x = " << &x <<endl;
        
    }
    X(X&& x)
    {
        cout << this << '\t';
        cout << "Constuctor X(X&&)"<<endl;
        cout << "addr of X&& x = " << &x <<endl;
        this->m_x = x.m_x;
        x.m_x = nullptr;
    }
    X& operator=(const X& x) {
        cout << this << '\t';
        cout << "= copy operator"<<endl;
        m_x = x.m_x;
    }
    X& operator=(X&& x){
        cout << this << '\t';
        cout << "= move operator"<<endl;
    }
    X& operator++(){
        cout << this << '\t';
        *m_x++;
        cout << "++ operator"<<endl;
        return *this;
    }
    ~X() {
        cout << this << '\t';
        cout << "Destructor"<<endl;
        if(m_x)
            delete m_x;
        else
            cout << "m_x null\t";

    }
    int* m_x = nullptr;
};


int main() {
    X x(X{});
}

程序输出

0x7ffcc5a0b150  Constuctor X()
0x7ffcc5a0b150  Destructor
m_x null 

原因解释

你遇到的是C++标准明确允许的复制消除(Copy Elision),具体属于临时对象消除的优化场景。

按照未优化的逻辑,X x(X{});确实会先调用默认构造创建临时对象X{},再通过移动构造函数用这个临时对象初始化x。但编译器有权直接跳过临时对象的创建步骤,直接在x的内存空间上执行默认构造——相当于把代码优化成了X x;,这样就省去了临时对象的构造、移动构造和析构流程,所以你只看到一次默认构造和对应的析构。

这种优化优先级极高,哪怕你的移动/复制构造函数包含打印日志这类副作用,编译器也可以选择执行该优化。如果想验证原本的执行流程,可以通过编译参数禁用该优化:

  • GCC/Clang:添加-fno-elide-constructors
  • MSVC:添加/Od(禁用所有优化)

启用禁用参数后,程序会按照你预期的流程运行:先构造临时对象,再调用移动构造初始化x,最后分别析构临时对象和x。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 16:06:21