首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C++返回值优化

C++返回值优化
EN

Stack Overflow用户
提问于 2013-10-19 00:03:42
回答 6查看 9.4K关注 0票数 10

这段代码:

代码语言:javascript
复制
#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();
    }
}

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

怎么回事?我如何才能从这样的函数返回一个向量(或任何其他对象),而不必每次都分配它?

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

EN

回答 6

Stack Overflow用户

发布于 2013-10-19 00:13:42

调用函数时,对于像std::vector<T>这样的返回类型,编译器会为返回的对象提供内存。被调用的函数负责构造它在这个内存插槽中返回的实例。

RVO/NRVO现在允许编译器省略创建本地临时对象,从它复制构造内存插槽中的返回值,析构临时对象,最后返回给调用者。相反,被调用的函数只是在返回槽的内存中直接构造本地对象,在函数结束时,它只是返回。

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

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

代码语言:javascript
复制
std::vector<float> v = getstdvec();

但是您的原始代码使用一个循环,并且在每次迭代中,需要构造来自getstdvec()的结果,并将此临时结果分配给v。RVO/NRVO不可能删除它。

票数 21
EN

Stack Overflow用户

发布于 2013-10-19 00:08:22

你可以通过reference...copy来传递,省略使得v= getstdvect()将v(在你的main中)直接分配给v(在你的getstdvec()中),并跳过通常与按值返回相关的副本,但它不会跳过你函数中的v(4)。为了做到这一点,您需要通过引用获取向量:

代码语言:javascript
复制
#include <vector>
void getstdvec(std::vector<float>& v){
  v.resize(4);//will only realocate if v is wrong size
  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)
    getstdvec(v);
}
票数 3
EN

Stack Overflow用户

发布于 2013-10-19 00:09:57

你在你的循环中做拷贝赋值,而不是拷贝构造。RVO优化只适用于从返回值构造变量,而不是赋值给它们。

我不太明白你想解决的真正问题是什么。有了更多的细节,也许可以提供一个很好的答案来解决您的潜在问题。

按照目前的情况,要以这种方式从函数返回,您需要创建一个临时向量,以便在每次调用函数时返回。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/19454068

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档