删除拷贝构造函数后std::make_unique编译失败的原因及疑问
C++删除拷贝构造函数后移动构造函数的隐式生成问题
代码示例与问题现象
无法编译的代码
struct A { A() = default; A(const A& other) = delete; }; int main() { auto a = A(); auto u = std::make_unique<A>(std::move(a)); }
这段代码在支持C++17的blaze编译器下编译失败,错误信息为:call to implicitly-deleted copy constructor
可以编译的代码
struct A { A() = default; A(const A& other) = delete; A(A&& other) = default; }; int main() { auto u = std::make_unique<A>(A()); }
疑问
- 第一段代码明明使用了
std::move(a)将对象转为右值,为什么不调用移动构造函数,反而触发拷贝构造函数的错误? - 删除拷贝构造函数会导致移动构造函数被隐式删除吗?为什么显式添加
A(A&& other) = default;就能解决编译问题?
解答
C++标准的隐式生成规则
当类中存在用户显式声明的拷贝构造函数(包括被删除的版本)时,编译器不会自动生成默认的移动构造函数。这是C++11及后续标准的明确规定——拷贝操作的用户声明会抑制移动操作的隐式生成。第一段代码编译失败的原因
在第一段代码中,struct A仅删除了拷贝构造函数,没有显式声明移动构造函数,因此编译器不会为它生成默认的移动构造函数。当调用std::make_unique<A>(std::move(a))时,虽然std::move(a)将a转为右值,但由于没有可用的移动构造函数,编译器会尝试回退到拷贝构造函数来完成对象构造。但拷贝构造函数已经被显式删除,最终触发了“调用被隐式删除的拷贝构造函数”的错误。第二段代码编译通过的原因
第二段代码中显式添加了A(A&& other) = default;,这会要求编译器生成符合默认行为的移动构造函数。此时std::make_unique<A>(A())可以通过移动构造函数来传递右值临时对象,因此编译正常通过。
内容的提问来源于stack exchange,提问作者Nimrod Fiat
相关产品推荐
相关产品推荐

