为何C++中调用移动构造函数而非默认拷贝构造函数?
C++20中拷贝构造函数与构造函数模板的调用疑惑
我使用g++.exe -std=c++20编译以下代码:
#include <iostream> using namespace std; class A { public: A() = delete; A(int value) : value(value) {} // A(auto &other) { // cout << "Copy constructor called..." << endl; // value = other.value; // } void operator=(const auto &other) = delete; A(auto &&other) { cout << "Move constructor called..." << endl; value = other.value; } ~A() { cout << "Destructor called..." << endl; } friend ostream &operator<<(ostream &os, const A &a); private: int value; }; ostream &operator<<(ostream &os, const A &a) { os << a.value; return os; } int main() { A p1(2); cout << "p1: " << p1 << endl; A p2(p1); cout << "p2: " << p2 << " p1: " << p1 << endl; return 0; }
注释掉拷贝构造函数时的输出
Move constructor called... p2: 2 p1: 2 Destructor called... Destructor called...
取消注释拷贝构造函数后的输出
p1: 2 Copy constructor called... p2: 2 p1: 2 Destructor called... Destructor called...
我疑惑为何编译器此时不调用默认拷贝构造函数(仅在删除移动构造函数或修改其参数为const时才会调用默认拷贝构造函数)。
问题解析
核心原因是你使用的是模板构造函数,而非C++标准定义的移动/拷贝构造函数:
模板构造函数的匹配优先级更高
你定义的A(auto &&other)是模板构造函数,并非标准移动构造函数(标准移动构造函数签名必须为A(A&&))。编译器仍会生成默认的拷贝构造函数A(const A&),但在A p2(p1)的场景中,p1是非常量左值,模板构造函数会被实例化为A(A&),这个签名比默认的A(const A&)匹配度更高,因此编译器选择调用该模板构造函数,而非默认拷贝构造函数。自定义模板拷贝构造函数的优先级
当你取消注释A(auto &other)时,该模板构造函数会被实例化为A(A&),同样比默认的A(const A&)匹配优先级更高,因此编译器会调用你自定义的这个构造函数。为何修改参数或删除移动构造函数后会调用默认拷贝构造函数
若将模板构造函数的参数改为const auto &&,实例化后会得到A(const A&&),无法匹配非常量左值p1;此时没有更匹配的构造函数,编译器才会选择默认生成的A(const A&)拷贝构造函数。而删除真正的移动构造函数(A(A&&))并不会影响模板构造函数的匹配逻辑,你观察到的现象本质还是模板构造函数是否能匹配左值参数的问题。
内容的提问来源于stack exchange,提问作者user2565010
相关产品推荐
相关产品推荐

