您现在的位置是:首页 >技术杂谈 >C++编程法则365条一天一条(358)copy elision(返回值优化NVO和具名返回值优化NRVO)网站首页技术杂谈

C++编程法则365条一天一条(358)copy elision(返回值优化NVO和具名返回值优化NRVO)

奇妙之二进制 2023-05-12 20:15:03
简介Copy elision 不同于 move semantics(移动语义),move semantics 强调的是使用右值引用来转移资源所有权,以达到减少对象拷贝和提高效率的目的,而 Copy elision 更注重在编译期间对代码的优化。Elision 是一个英文单词,指的是省略、删节或者忽略的意思。Copy elision的目标是减少临时变量的使用,即避免在进行函数返回时复制多个对象,尤其是当返回值的类型与所定义的对象的类型相同时,甚至连一个临时对象都不需要创建。这样就提高了运行时的效率。

参考:https://en.cppreference.com/w/cpp/language/copy_elision

Elision 是省略、删节或者忽略的意思。在C++中,Copy elision则是编译器优化技术的一种,该技术可以避免进行不必要的复制和移动操作,从而提高程序的性能和效率。

Copy elision的目标是减少临时变量的使用,即避免在进行函数返回时复制多个对象,尤其是当返回值的类型与所定义的对象的类型相同时,甚至连一个临时对象都不需要创建。这样就提高了运行时的效率。

Copy elision 是在 C++11 标准中引入的,并默认启用,但是也有一些例外情况,例如当构造函数包含副作用(side effects)时,copy elision可能就无法发生。

Copy elision 不同于 move semantics(移动语义),move semantics 强调的是使用右值引用来转移资源所有权,以达到减少对象拷贝和提高效率的目的,而 Copy elision 更注重在编译期间对代码的优化。

强制编译器实现的优化

返回纯右值(临时对象)时:

T f()
{
    return T();
}
 
f(); // only one call to default constructor of T

这样的优化叫NVO,RVO 是一种更为基本的优化,只要返回值是一个临时对象,且该对象没有被命名,编译器就必须使用 RVO 优化,以避免执行不必要的拷贝或移动操作。

初始化对象时,如果初始化器是一个纯右值,那么编译器也必须进行优化。

T x = T(); 

以上两个是编译器强制要做的优化。

非强制实现优化

在C++编程中,经常需要在函数中返回一个对象。当返回的对象是一个非易失性有自动存储期的对象,并且满足以下条件:

  • 不是函数参数或catch子句参数;
  • 其所属的类类型(忽略cv修饰符)与函数返回值类型相同。

这时,编译器会尝试进行一种名为"NRVO" (Named Return Value Optimization,具名返回值优化)的复制省略优化。该优化允许编译器在返回该对象时避免执行额外的拷贝或移动操作,并将对象直接构造在指定的内存位置,以提高程序的性能表现。

需要注意的是,NRVO 是一种可选的优化方式,不是强制性的。因此,即使满足了上述所有条件,编译器仍然可以选择执行拷贝或移动操作,而不是使用 NRVO 优化。

NRVO 只是 RVO 的一种扩展,其优化的是一个具名的非易失性有自动存储期的对象,如果某个函数返回了这个具名对象,编译器会尝试使用 NRVO 避免对象拷贝或移动。

Noisy f()
{
    Noisy v = Noisy(); // copy elision when initializing v
                       // from a temporary (until C++17) / prvalue (since C++17)
    return v; // NRVO from v to the result object (not guaranteed, even in C++17)
}             // if optimization is disabled, the move constructor is called
风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。