C++返回值优化

Aur*_*ius 10 c++ return-value-optimization copy-elision

这段代码:

#include <vector>

std::vector<float> getstdvec() {
    std::vector<float> v(4);

    v[0] = 1;
    v[1] = 2;
    v[2] = 3;
    v[3] = 4;

    return v;
}

int main() {
    std::vector<float> v(4);

    for (int i = 0; i != 1000; ++i)
    {
        v = getstdvec();
    }
}
Run Code Online (Sandbox Code Playgroud)

我在这里的错误理解是函数getstdvec不应该实际分配它返回的向量.当我在valgrind/callgrind中运行它时,我看到有1001个调用malloc; 1表示main中的初始向量声明,1000表示每次循环迭代.

是什么赋予了?如何从这样的函数返回向量(或任何其他对象)而不必每次都分配它?

编辑:我知道我可以通过引用传递向量.我的印象是,有可能(甚至更可取)编写这样的函数,它返回一个对象而不会产生不必要的分配.

Dan*_*rey 18

当您调用函数时,对于返回类型,例如std::vector<T>编译器为返回的对象提供内存.被调用的函数负责构造它在该内存槽中返回的实例.

现在,RVO/NRVO允许编译器省略创建本地临时对象,从中复制构造内存槽中的返回值,破坏临时对象并最终返回给调用者.相反,被调用的函数只是直接在返回槽的内存中构造本地对象,而在函数的末尾,它只返回.

从调用者的角度来看,这是透明的:它为返回的值提供内存,当返回的函数返回时,有一个有效的实例.调用者现在可以使用此对象,并负责调用析构函数并在以后释放内存.

这意味着RVO/NRVO仅在您调用函数来构造新实例时工作,而不是在您分配它时.以下是可以应用RVO/NRVO的示例:

std::vector<float> v = getstdvec();
Run Code Online (Sandbox Code Playgroud)

但是原始代码使用循环,并且在每次迭代中,getstdvec()需要构造结果并将此临时值分配给v.RVO/NRVO无法将其删除.


Dwe*_*rly 1

最简单的答案是将已经创建的向量对象传递给函数。

std::vector<float> getstdvec(std::vector<float> &myvec){
Run Code Online (Sandbox Code Playgroud)

在这种情况下,你实际上不必归还它,所以

void getstdvec(std::vector<float> &myvec){
Run Code Online (Sandbox Code Playgroud)