C++20中使用auto初始化对象是否一定会调用移动构造函数?
结论
你的理解不正确,C++20标准下两种写法的执行开销完全一致,不存在任何性能差异。
规则依据
C17引入的强制复制/移动消除规则在C20中完全保留,该规则明确要求:当一个同类型的纯右值被用于初始化对象时,编译器必须直接在目标对象的内存空间上构造对象,跳过中间临时对象的构造、以及后续的复制/移动构造步骤,不需要考虑移动构造函数是否有副作用,该优化是强制要求的,不是可选优化。
你给出的第一种写法:
auto t{ std::thread(hello) };
其中std::thread(hello)是std::thread类型的纯右值,用于初始化同类型的变量t,完全符合强制移动消除的触发条件,编译器会直接在t的内存地址上构造接收hello作为参数的std::thread对象,全程仅调用一次构造函数,不会产生中间临时对象,也不会调用移动构造函数。
两种写法的差异
两种写法仅存在编码风格上的区别,性能、运行逻辑完全一致:
- 第一种写法遵循「几乎总是auto」的编码规范,变量类型由右侧表达式自动推导
- 第二种写法显式标注变量类型,代码可读性更偏向类型优先的风格
验证方式
你可以通过自定义包装类的方式验证行为,示例如下:
#include <iostream> struct Test { Test(int) { std::cout << "普通构造\n"; } Test(const Test&) = delete; Test(Test&&) noexcept { std::cout << "移动构造\n"; } ~Test() { std::cout << "析构\n"; } }; int main() { auto t{ Test(1) }; // C++17及以后编译运行,只会输出「普通构造」+「析构」,不会触发移动构造 return 0; }
上述代码即使删除了拷贝构造、移动构造带有打印副作用,也可以正常编译运行,且不会触发移动构造调用,足以证明消除是强制生效的。
内容的提问来源于stack exchange,提问作者hescul
相关产品推荐
相关产品推荐

