返回值优化RVO

RVO优化是什么?

返回值优化(Return Value Optimization,简称RVO)是一种编译器优化机制,主要是为了减少临时对象的产生。
什么是临时对象?

C++中的临时对象是不可以见的,与我们平常说的局部对象是不同的:

template<class T>
void swap(T& object1, T& object2) {
    T temp = object1;
    object1 = object2;
    object2 = temp;
}

上面的temp并不是临时对象,而是一个局部变量。

什么时候会产生临时对象?

1)为了函数调用能够成功而实施的隐式类型转换(implicit type conversions)
2)当函数返回对象的时候
首先考虑第一种情况,为了让函数调用成功而产生临时对象,这种情况发生在传递某对象给函数的参数,而其类型与它即将绑定上去的参数类型不同,此时就会产生临时对象。只有当对象以by-value方式传递或者当对象被传递给一个reference-to-const参数时,这些转换才会发生,如果对象被传递给一个reference-to-non-const参数,并不会发生转换,
第二种是会产生临时对象的情况则是当函数返回一个对象时。
临时对象可能很耗成本,所以尽量消灭临时对象的产生,任何时候reference-to-const参数都极有可能产生一个临时对象,绑定至该参数上。任何时候只要 函数返回一个对象,就会产生临时对象,并于稍后销毁。

下面简单了解一下C++中的函数是如何返回一个对象的。(以下的内存布局以Linux为例,Windows中程序的内存布局和Linux下略有不同,本文不再详述)
例如下面的程序:

class Widget{};
Widget f(Widget u){
   Widget w;
   return w;
} 

在使用这个函数的时候
如果是如下图左侧调用函数f的,实际上在内存中的栈中是如下变化的:
函数调用内存图
如果我们在Widget的拷贝构造函数和赋值构造函数中加入一个输出的flag:

class Widget {
public:
    Widget() {
        cout << "construction" << endl;
    }
    Widget(const Widget&w) {
        cout << "copy" << endl;
    }
    Widget& operator=(const Widget& w){
        if (this != &w) {
        }
        cout << "copy assignment" << endl;
        return *this;
    }
};
Widget f(Widget u) {
    Widget w;
    return w;
}
int main()
{
    {
        Widget x;
        Widget y;
        y = f(x);
    }
    system("pause");
    return 0;
}

那么可以轻松的在输出中看到,
结果图1
第三个construction是函数f内在构建Widget对象的时候,然后就是到了return的节奏,这时候为了
我们可以把上面构造的顺序列出来:

x构造 -> y构造 -> u通过x拷贝构造 -> w构造 -> 临时对象 通过w拷贝构造 -> u析构 -> w析构 -> y通过赋值运算符获取临时对象的值 -> 临时对象析构 -> y析构 -> x析构

如果是按照下面调用:
这里写图片描述
如果是上面这种调用,那么可以的到如下:
这里写图片描述
如果是下面这种调用:
这里写图片描述
得到输出结果:
这里写图片描述
上面的内存布局中并未考虑参数传递,因为更加具体的内存布局会在程序的内存布局中讲到。

返回值优化RVO

从上面的内存过程中,我们显然看到了很多不必要的拷贝,那么下面就应该想办法优化这个事情。当函数以by-value方式返回对象,总是会产生这样的临时对象。那么如何减少临时对象的产生,就能够很有效的减少copy构造函数的调用,从而减少copy函数带来的开销(假设我们的类数据成员比较多,构建比较复杂,那么copy构造函数带来的开销就会很大)。
编译器开启RVO以后会将return表达式所定义的对象构建在接受返回值的变量内:

Widget f(x);
Widget y=f(x);

在上面的代码中,由于开启了RVO,编译器会将return表达式所定义的对象构建在y的内存内,如果编译器这么做,调用函数f时的临时队形总成本为0,也就是说没有任何临时对象被产生出来。取而代之的是付出一个构造函数(用来产生y)的代价。

### 返回值优化 (RVO) 的概念 返回值优化(Return Value Optimization, RVO)是一种由编译器执行的技术,旨在减少或消除函数返回对象时不必要的拷贝操作。当一个函数返回局部创建的对象而不是指针或引用时,通常会产生临时对象并触发复制构造函数。然而,在许多情况下,这种额外的复制是没有必要的。 通过实施 RVO,编译器可以在特定条件下直接将目标位置作为构建最终结果的地方,从而跳过中间步骤中的显式副本动作[^1]。 ### RVO 的工作原理 具体来说,对于那些返回新实例而非现有实体的情况,编译器可能会采取措施让被调用方直接在其外部预期接收该值的位置上建立所需的数据结构。这意味着: - 函数内部不会真正创建独立于外界存在的临时对象; - 调用者指定的目标地址成为实际存储空间所在之处; - 构造过程发生在最终目的地处,避免了后续转移带来的开销。 例如,在下面的例子中 `func()` 方法内声明了一个名为 `temp` 的变量,并将其作为返回值传递给外面的世界;但是由于启用了 RVO 机制,则实际上并没有发生任何真正的“返回”。 ```cpp A func() { A temp(69); return temp; } ``` 这里展示的是如何利用 C++ 中的语法特性来帮助实现更高效的内存管理策略[^5]。 ### 应用场景与限制条件 尽管大多数现代编译器都能够很好地识别何时适合应用此优化方法,但在某些复杂情形下仍可能存在局限性。例如,如果涉及多态行为或是虚继承关系的话,那么即使是最先进的工具也可能无法安全地省略掉所有的潜在复制活动。此外,当面对含有异常处理逻辑或者依赖于副作用表达式的语句块时,同样难以保证完全去除所有形式上的数据传输环节[^4]。 值得注意的是,虽然 NRVORVO 是两种不同类型的优化方式,但它们共同作用于提升整体效率方面有着重要意义,特别是在资源受限环境中尤为明显[^3]。 ### 编译器的支持情况 随着 C++ 标准的发展以及各版本之间的演进,有关 RVO 的支持程度也在不断变化之中。早期的标准如 C++98 并未强制规定此类特性的存在与否及其表现形态;而到了后来诸如 C++17 这样的更新则引入了一些改进措施使得更多场合下的无损转换成为了可能。不过无论如何,始终建议开发者们关注所使用的具体开发环境所提供的文档说明以获取最新信息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值