为什么显式默认的析构函数会改变C++类的移动语义?
测试代码
#include <iostream> #include <utility> struct A { A() = default; A(A const&) { std::cout << "A(A const&)" << std::endl; } A(A&&) { std::cout << "A(A&&)" << std::endl; } }; struct B { A a; ~B() = default; }; struct C { A a; }; int main() { auto b1 = B{}; auto b2 = B(std::move(b1)); // 调用A的拷贝构造函数A(A const&) auto c1 = C{}; auto c2 = C(std::move(c1)); // 调用A的移动构造函数A(A&&) }
差异原因
这个现象是C++标准对特殊成员函数隐式生成规则的明确规定导致的:
- 只要类存在用户声明的析构函数,编译器就不会为该类隐式生成移动构造函数和移动赋值运算符。注意:用
= default显式要求生成默认析构函数,也属于「用户声明析构函数」的范畴,同样会抑制移动函数的隐式生成。
类B的执行逻辑
B显式声明了~B() = default;,符合抑制移动函数生成的条件,没有可用的移动构造函数。此时B(std::move(b1))传入的右值会自动匹配到B隐式生成的拷贝构造函数(拷贝构造的生成不会被用户声明的析构函数抑制),拷贝构造函数会对成员a执行拷贝操作,因此调用A的拷贝构造。
类C的执行逻辑
C没有用户声明任何特殊成员函数,编译器会正常隐式生成移动构造函数,该移动构造会对每个类成员执行移动操作,因此调用A的移动构造。
内容的提问来源于stack exchange,提问作者xmllmx
相关产品推荐
相关产品推荐

