在 Visual Studio 2022 版本 17.4 及更高版本中,可以使用 编译器选项显式启用可选的复制或移动引入行为
/Zc:nrvo
。 此选项默认处于关闭状态,但在使用
/O2
选项、
/permissive-
选项或更高版本
/std:c++20
进行编译时会自动设置。 在 下
/Zc:nrvo
,将尽可能执行复制和移动。 还可以使用
/Zc:nrvo-
选项显式禁用可选的复制或移动传送。 这些编译器选项仅控制可选的复制或移动传送。 无法禁用由 C++ 标准) 指定的强制复制或移动 (。
强制复制和移动
当返回的值作为 return 语句的一部分初始化时,C++ 标准需要复制或移动请求。 例如,当函数返回通过使用
return ExampleType();
返回的 时
ExampleType
,这是必需的。 MSVC 编译器始终在需要时对
return
语句执行复制和移动,即使在 下
/Zc:nrvo-
也是如此。
可选复制和移动
return
当语句包含非基元类型的表达式时,其执行会将表达式结果复制到调用函数的返回槽中。 编译器调用返回类型的复制或移动构造函数。 然后,在退出函数时,将调用函数局部变量的析构函数,其中包括表达式中命名的任何变量。
C++ 标准允许 (但不要求编译器) 直接在调用函数的返回槽中构造返回的对象。 此构造跳过 (或
)
作为 语句的
return
一部分执行的复制或移动构造函数。 与大多数其他优化不同,允许此转换对程序的输出产生可观察的影响。 也就是说,复制或移动构造函数和关联的析构函数将少调用一次。 该标准仍要求已命名的返回变量具有定义的复制或移动构造函数,即使编译器在所有情况下都删除构造函数。
在 Visual Studio 2022 版本 17.4 之前的版本中,当禁用优化 ((例如,在) 标记
#pragma optimize("", off)
的函数下
/Od
或中)时,编译器仅执行强制复制和移动。 在 下
/O2
,如果满足以下所有条件,则较旧的编译器在优化函数中返回命名变量时执行可选的复制或移动操作:它没有循环或异常处理,它不返回具有重叠生存期的多个符号,类型的复制或移动构造函数没有默认参数。
Visual Studio 2022 版本 17.4 增加了编译器在 下
/Zc:nrvo
执行可选复制或移动位置的数目,无论是显式启用,还是使用
/O2
、
/permissive-
或更高版本
/std:c++20
选项自动启用。 在 下
/Zc:nrvo
,编译器在返回任何函数的命名变量时执行可选的复制或移动操作:它没有 () 之前的循环或异常处理;它从循环返回变量;具有异常处理;返回类型的复制或移动构造函数具有默认参数。 当应用 时、函数返回具有重叠生存期的多个符号或引发命名变量时
/Zc:nrvo-
,从不执行可选的复制或移动请求。
有关 下
/Zc:nrvo
强制复制和可选复制的详细信息和示例,请参阅 C++ 团队博客中的
改进复制和移动 Elision
。
在 Visual Studio 中设置此编译器选项
打开项目的“属性页” 对话框。 有关详细信息,请参阅
在 Visual Studio 中设置 C++ 编译器和生成属性
。
选择“配置属性”>“C/C++”>“命令行”属性页。
在
“其他选项”
中,添加
/Zc:nrvo
或
/Zc:nrvo-
。 选择“确定”或“应用”以保存更改。
/Zc
(一致性)
/permissive-
/std
(指定语言标准版本)