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

为何C++移动构造函数未被调用?

问题

定义了一个同时包含拷贝构造函数和移动构造函数的类,拷贝构造函数可正常运行,但调用移动构造函数时无法生效。代码如下:

#include <iostream>

class A{

        public:
                A() = default;

                A(A& a){
                        std::cout << "Copy constructor." << std::endl;
                };

                A(A&& a){
                        std::cout << "Move constructor." << std::endl;
                };
};


int main(int argc, char *argv[]){

        auto a = A(A());
        
        std::cout << "here" << std::endl;       

        auto b = A(a);

        return 0;
}

原本认为auto a = A(A());应该调用移动构造函数(因为A()是右值),但实际输出为:

[amirreza@localhost tmp]$ ./a.out 
here
Copy constructor.

使用gcc 10.3.1版本,未显式指定C++版本,想知道假设是否错误。

原因分析与解决方法

1. 拷贝构造函数的定义问题

你的拷贝构造函数参数是A&(非const左值引用),不符合C++标准中拷贝构造函数的常规定义(标准拷贝构造参数应为const A&)。这种写法会干扰编译器对重载函数的匹配逻辑,同时也会导致一些右值场景下的意外行为。

2. 返回值优化(RVO)与C++17强制省略

gcc 10.3.1默认启用C17标准,在C17中,auto a = A(A());属于强制拷贝省略场景:编译器会直接在a的内存位置构造对象,完全跳过临时对象的创建、移动或拷贝步骤,因此不会触发移动构造函数的调用,自然看不到对应的日志输出。

即使在C++11/14中,编译器也会默认开启返回值优化(RVO),同样会省略移动/拷贝过程,除非显式禁用优化。

3. 验证移动构造函数的正确方式

如果想要观察到移动构造函数的调用,可以做以下调整:

  • 修改拷贝构造函数为标准形式:
    A(const A& a){
        std::cout << "Copy constructor." << std::endl;
    };
    
  • 编译时禁用返回值优化,并指定C++版本,比如:
    g++ -std=c++17 -fno-elide-constructors your_code.cpp -o a.out
    
  • 或者用更直接的方式触发移动,比如使用std::move转换左值为右值:
    A temp;
    auto a = std::move(temp); // 这里会调用移动构造函数
    

4. 关于auto b = A(a);的行为

这里a是左值,所以编译器会匹配参数为A&的拷贝构造函数,这部分行为是符合预期的。

内容的提问来源于stack exchange,提问作者Amir reza Riahi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 17:31:08