C++17中移动省略(MOVE elision)有哪些变更?移动构造省略是否被保证?
C++17移动省略规则解答
核心规则调整
C++17引入的保证拷贝/移动省略不是可选的编译器优化,而是语言层面强制要求的规则:它重新定义了纯右值的语义,纯右值不再代表一个已经构造完成的临时对象,而是一个“待执行的对象初始化表达式”,只有在必须实体化出对象的时候才会触发构造。
这个规则不受-fno-elide-constructors编译选项影响,因为它不属于可选优化范畴,是语言强制要求的行为。
测试场景差异原因
你的测试代码中两种传参方式的行为差异可以直接用上述规则解释:
#include <iostream> struct NonCopyable { NonCopyable() = default; NonCopyable(const NonCopyable&) = delete; NonCopyable(NonCopyable&& other) noexcept { std::cout << "Move ctor\n"; } }; void func_by_value(NonCopyable cp) { auto x = std::move(cp); } void func_by_rvalue_ref(NonCopyable&& cp) { auto x = std::move(cp); } int main() { std::cout << "Pass by value:\n"; func_by_value(NonCopyable()); std::cout << "\nPass by rvalue_ref\n"; func_by_rvalue_ref(NonCopyable()); }
按值传参场景 func_by_value(NonCopyable())
- C++11/14规则:
NonCopyable()先构造一个纯右值临时对象,再用这个临时对象移动构造函数的按值参数cp,触发第一次移动构造;函数内部auto x = std::move(cp)触发第二次移动构造,总共2次移动调用。 - C++17规则:纯右值
NonCopyable()直接在参数cp的内存地址上构造对象,不需要额外执行一次移动构造初始化参数,因此只剩下函数内部的1次移动构造调用。
右值引用传参场景 func_by_rvalue_ref(NonCopyable())
参数是右值引用,只需要绑定到临时对象不需要构造新的对象,所以C11和C17下行为一致,只有函数内部的1次移动构造调用。
补充注意点
保证省略仅适用于纯右值直接初始化同类型对象的场景,包括:
- 函数按值返回纯右值
- 用纯右值初始化按值传递的函数参数
- 用纯右值直接构造同类型对象
如果是将亡值(比如std::move返回的右值引用),则不适用保证省略规则,是否省略还是取决于编译器优化。
内容的提问来源于stack exchange,提问作者bielu000
相关产品推荐
相关产品推荐

