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

函数返回值赋值给变量时,拷贝与移动构造函数调用逻辑疑问

C++返回值与构造函数调用问题

问题

  • 将函数返回值赋值给变量时,会调用拷贝构造函数还是移动构造函数?
  • 已确认func_test的返回值为右值,为何未定义移动构造函数时,语句test a=func_test();会调用拷贝构造函数,定义移动构造函数后则调用移动构造函数?

示例代码

#include <stdio.h>
#include <iostream>
#include <typeinfo>
using namespace std;

class test
{
public:
    int b;
    int* p;
    test() :b(1) {
        p = new int(2);
    }
    ~test()
    {
        delete p;
        cout << this << "delete" << endl;
    }
    test(const test & a)
    {
        b = a.b;
        int tmp = *a.p;
        p = new int(tmp);
        cout << "copy constructor " << endl;
    }
    //test(const test&& d)
    //{
    //  cout << "move constructor" << endl;
    //  p = d.p;
    //  b = d.b;
    //}
};

test func_test()
{
    test a;
    return a;
}
int main()
{
    test a=func_test();
}

解答

问题1:返回值赋值时的构造函数选择

函数返回值赋值给变量时,优先调用移动构造函数,但需满足两个核心条件:

  1. 返回的对象是可移动的右值(比如函数返回的临时对象);
  2. 类定义了非const的移动构造函数(注意你注释的代码里用了const test&&,这不符合常规移动逻辑——移动操作通常需要修改源对象,比如接管指针后将源对象指针置空,避免重复析构)。

如果没有定义移动构造函数,编译器会退而求其次调用拷贝构造函数,因为拷贝构造函数的const test&参数是"万能引用",可以接收左值和右值。

问题2:为何定义移动构造函数后才触发调用

func_test返回的临时对象确实是右值,但在没有移动构造函数时,这个右值只能匹配到拷贝构造函数的const test&参数——这是C++的规则:const左值引用可以绑定任何类型的表达式,包括右值。

当你定义了正确的移动构造函数(参数为test&&,不带const),编译器会优先选择匹配右值引用的版本,因为它是更精准的匹配:纯右值直接对应test&&,不需要降级使用const test&。

另外补充两个关键点:

  • 你的注释代码里的移动构造函数有问题,正确写法应该给源对象的指针置空:
    test(test&& d)
    {
        cout << "move constructor" << endl;
        p = d.p;
        d.p = nullptr; // 避免源对象析构时重复释放内存
        b = d.b;
    }
    
  • 编译器默认会开启返回值优化(RVO/NRVO),直接在目标变量的内存上构造返回值,此时不会调用任何构造函数。如果要观察拷贝/移动的调用情况,需要关闭优化(比如GCC加编译参数-fno-elide-constructors)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 18:15:52