为何编译器调用move后选择拷贝构造函数?右值引用相关疑问
嘿,我来帮你把这些C++里的细节拆解清楚,一个个解决你的疑问~
关于拷贝构造、移动构造与右值引用的疑问解答
1. 为什么编译器会选择拷贝构造而非报错?
当你手动实现了拷贝构造函数后,C++编译器确实会自动禁用默认的移动构造函数——这是标准规定的行为,目的是避免自动生成的移动构造和你自定义的拷贝构造逻辑冲突。
但这里有个关键的兼容设计:右值在找不到匹配的移动构造函数时,会尝试绑定到const T&类型的参数,也就是你的拷贝构造函数。因为const左值引用是可以接受右值的(临时对象、字面量这些都是右值),编译器会把这个右值隐式转换为可被const T&绑定的形式,进而调用拷贝构造。
这种设计是为了保证新旧代码的兼容性:在C++11引入移动语义之前,所有对象拷贝都是用拷贝构造,所以即使现在你没写移动构造,代码依然能像以前一样正常工作,而不是直接报错。
2. 右值引用能否作为左值引用的参数?
这得分两种情况看:
- 如果是
const左值引用(const T&):完全可以!C++标准允许右值绑定到const左值引用上,这也是上面拷贝构造能被调用的核心原因。这种设计让你可以用同一个函数同时处理左值和右值,不用单独写重载。 - 如果是非
const左值引用(T&):不行!非const左值引用要求绑定到一个可修改的左值(比如有名字的变量),右值是临时的、不可被修改的(或者说修改了也没意义),所以编译器会直接报错,提示「无法将右值绑定到非const左值引用」。
结合你的输出结果「Thanks」来理解
假设你的代码大概是这样的:
#include <iostream> class Demo { public: Demo() {} // 自定义拷贝构造,输出Thanks Demo(const Demo&) { std::cout << "Thanks" << std::endl; } // 没有定义移动构造函数 }; int main() { // 用临时右值对象初始化obj Demo obj = Demo(); return 0; }
这里Demo()是一个临时右值,因为没有移动构造函数,编译器就会调用你自定义的拷贝构造函数,所以输出了「Thanks」。
内容的提问来源于stack exchange,提问作者DsCpp
相关产品推荐
相关产品推荐

