函数返回值赋值给变量时,拷贝与移动构造函数调用逻辑疑问
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:返回值赋值时的构造函数选择
函数返回值赋值给变量时,优先调用移动构造函数,但需满足两个核心条件:
- 返回的对象是可移动的右值(比如函数返回的临时对象);
- 类定义了非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
相关产品推荐
相关产品推荐

