为何移除move constructor后调用copy constructor而非默认move constructor?
关于C++移动构造函数调用的疑问解答
嘿,这个问题问得特别到位,刚好戳中了C++11里默认移动构造函数生成的一个容易被忽略的规则点!我来一步步给你拆解清楚:
先理清你的代码执行场景
你用了编译参数-fno-elide-constructors,这会关闭返回值优化(RVO),所以ABC c1 = ABC()的执行流程会分成两步:
- 创建临时的
ABC()对象,触发默认构造函数; - 把这个临时右值对象“转移”给
c1,这时候编译器会尝试调用移动构造或拷贝构造。
核心原因:默认移动构造函数的生成规则
C++11标准明确规定:当你自定义了拷贝构造函数、拷贝赋值运算符、析构函数中的任意一个时,编译器不会自动生成默认的移动构造函数。
回到你的代码里:
- 当你保留自定义的
move constructor时,编译器会优先用它来处理右值临时对象,所以输出move construction; - 当你移除自定义移动构造后,你的类里还存在自定义的拷贝构造函数!这就触发了上面的规则——编译器不会再帮你生成默认的移动构造函数。
这时候,当需要处理右值临时对象时,因为没有可用的移动构造函数,编译器会退而求其次:右值可以被绑定到const ABC&类型的参数(也就是拷贝构造函数的参数),所以最终调用的是拷贝构造函数,输出copy construction。
验证:如何让编译器生成默认移动构造?
如果你想在保留自定义拷贝构造的同时,让编译器生成默认移动构造,可以显式声明:
#include <iostream> class ABC { public: ABC() { std::cout<< "default construction" << std::endl; } ABC(const ABC& a) { std::cout << "copy construction" << std::endl; } // 显式让编译器生成默认移动构造 ABC(ABC&&) = default; }; int main() { ABC c1 = ABC(); return 0; }
用同样的编译参数-fno-elide-constructors -std=c++11编译运行,就会输出:
default construction move construction
给新手的小总结
记住这个关键规则:只要你手动定义了拷贝相关的成员(拷贝构造、拷贝赋值、析构),编译器就不会自动生成移动构造/移动赋值——这是C++11为了兼容旧代码的行为而设计的。如果需要移动语义,要么自己写移动构造,要么显式用= default;让编译器帮你生成。
内容的提问来源于stack exchange,提问作者sunshilong369
相关产品推荐
相关产品推荐

