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

为何C++编译器未在构造函数参数中自动使用移动构造?

问题:为何C++编译器未自动将构造函数参数移动到成员变量?

我一直认为C++编译器会在如下场景中使用移动构造:

#include <string>

struct A {
    std::string str;
    explicit A(std::string s) : str(s) {}  // 这里的s不会被移动到str里吗?
};

std::string foo(int x) {
    return std::to_string(x);
}

int main() {
    A a(foo(10));
    return a.str.size();
}

但通过Godbolt验证发现实际并非如此:在-O9优化级别下,将构造函数改为explicit A(std::string s) : str(std::move(s)) {}后生成的代码体积更小。我原以为两种写法等价,疑惑作为即将销毁的临时对象,s的值为何不会被自动移动到str中?


解答

核心原因是:构造函数的形参s是命名左值对象,而非临时亡值,C++标准不允许编译器自动将其当作右值处理,因此不会触发移动构造。

具体细节拆解:

  • 调用A a(foo(10))时,foo返回的临时字符串确实会被移动构造到形参s中——这一步是合法的,因为临时对象属于亡值,初始化形参时优先用移动构造。
  • 但进入构造函数的初始化列表后,s是一个有明确名称的局部变量,属于左值。哪怕它在构造函数结束后就会被销毁,C++标准也规定编译器不能自动将左值视为亡值——这是为了避免意外修改左值的行为,保证代码的可预测性。
  • 因此str(s)会调用std::string的拷贝构造函数,需要分配内存并复制字符串内容;而str(std::move(s))是显式将s转换为亡值,触发移动构造函数,仅需转移字符串的底层指针,无需内存分配和复制,生成的代码自然更精简。

简单来说:左值哪怕即将销毁,也不会被自动当作右值,必须显式用std::move转换,才能触发移动语义。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 08:17:20