当前位置: 首页 > 科技观察

VisualStudio:优化copy-moveelision

时间:2023-03-19 18:56:53 科技观察

Scorpion为了能发帖,标题中的copy/moveelision是Copy/MoveElision的硬译,还请多包涵。我将在下文中同时使用这两个术语。VisualStudio中复制/移动省略号的更改在VisualStudio2022版本17.4预览版3中,我们显着增加了复制/移动省略号可用的情况,并让用户更好地控制是否启用这些转换。什么是复制/移动省略?当C++函数中的return关键字后跟一个非内置类型的表达式时,执行return语句会将表达式的结果复制到调用函数的返回槽(ReturnSlot)中。为此,将调用非内置类型的复制或移动构造函数。然后,作为退出函数的一部分,调用函数局部变量的析构函数,可能包括在return关键字后的表达式中命名的任何变量。C++规范允许编译器直接在调用函数的返回槽中构造返回的对象,从而省略作为返回的一部分执行的复制或移动构造函数。与大多数其他优化不同,此转换允许对程序的输出产生可观察到的效果——即,复制或移动构造函数和关联的析构函数可以被调用的次数减少一次。VisualStudio中的复制/移动省略C++标准要求编译器在将返回值初始化为返回语句的一部分时执行复制/移动省略(例如,当返回类型Foo的函数返回Foo()时)。MicrosoftVisualC++编译器总是根据需要对返回语句执行复制/移动省略,而不管传递给编译器的标志是什么。此行为保持不变。VisualStudio17.4Preview3中对可选复制/移动省略的更改当返回值是命名变量时,编译器可能会省略复制或移动,但这不是必需的。C++标准仍然要求为命名的返回变量定义一个复制或移动构造函数,即使编译器在所有情况下都省略了构造函数。在VisualStudio2022版本17.4预览版3之前,编译器只会在禁用优化(例如使用/Od编译器标志或使用#pragmaoptimize("",off))时强制执行复制/移动省略。使用/O2标志,编译器将执行可选的Copy/MoveElision以使用简单的控制流优化函数。从VisualStudio2022版本17.4预览版3开始,我们为开发人员提供了与新的/Zc:nrvo编译器标志保持一致的选项。默认情况下,当使用/O2标志/permissive-编译代码时,或者为/std:c++20或更高版本编译时,会传递/Zc:nrvo标志。传递此标志时,将在可能的情况下执行复制和移动省略。我们希望在未来的版本中默认启用/Zc:nrvo。或者,开发人员可以使用/Zc:nrvo-标志显式禁用可选的Copy/MoveElision。请注意,不能禁用强制复制/移动省略。在VisualStudio2022版本17.4预览版3中,当使用/Zc:nrvo、/O2、/permissive-或/std:c++20或更高版本标志启用可选复制/移动省略时,我们还添加了Copy的位置/MoveElision改变了。可选复制/移动省略示例可选复制/移动省略的最简单示例是以下函数:FooSimpleReturn(){Fooresult;返回结果;在这种情况下,如果传递了/O2标志,则早期版本的MSVC编译器已将结果复制或移动到返回槽中。在VisualStudio2022版本17.4预览版3中,如果传递了/permissive-、/std:c++20或更高版本或/Zc:nrvo标志,如果传递了/Zc:nrvo-标志,复制或移动也会被省略,保留复制或移动。从VisualStudio2022版本17.4预览版3开始,如果将/O2、/permissive-、/std:c++20或更高版本或/Zc:nrvo标志传递给编译器,而没有将/Zc:nrvo-标志传递给编译器,我们现在在以下其他情况下执行复制/移动省略。在循环中返回FooReturnInALoop(intiterations){for(inti=0;i