返回值或修改引用传递的参数是否更快?

Is it faster to return a value or modify a parameter passed by reference?

本文关键字:是否 参数 修改 引用 返回值      更新时间:2023-10-16

在我正在编写的程序中,我必须在函数之间传递大型数据结构(图像)。我需要我的代码在不同的操作系统上尽可能快(因此,我不能分析所有的测试用例)。我经常有这样的代码…

void foo() {
  ImageType img = getCustomImage();
}
ImageType getCustomImage() {
  ImageType custom_img;
  //lots of code
  return custom_img;
}

当然,ImageType img = getCustomImage();行将导致img的复制构造函数被调用,custom_img的返回值作为其参数。维基百科说,有些编译器甚至会对初始临时变量再次执行此操作!

我的问题:一般来说,通过使用引用传递而不是返回值来绕过这个开销(图像的复制构造函数很昂贵)是否更快…

void foo() {
  ImageType img;
  getCustomImage(img);
}
void getCustomImage(ImageType &img) {
  //code operating directly on img
}

我被告知,如果编译器支持返回值优化,那么应该没有区别。这是真的吗?现在我能(在合理的范围内)假设这一点吗?当速度很重要的时候,我应该如何组织我的程序

您应该编写可维护的代码,编译器在大多数情况下都很擅长为性能做正确的事情。如果你觉得事情进展缓慢,那就衡量一下表现,在你找到瓶颈之后,试着找出如何改进它。

您是对的,在逻辑上代码触发不同的复制结构:从custom_img到返回的临时对象,然后到调用者代码中的img对象,但事实是两个副本都将被省略。

按值返回default-construct + pass-by-reference的特殊情况下,我所知道的所有调用约定都通过让调用者分配内存并向被调用者传递一个隐藏指针来实现按值返回,这有效地实现了您将尝试做的事情。所以从性能的角度来看,它们基本上是相等的。

我在过去的两篇博客文章中写过这个(函数参数和返回值中的值语义):

  • 命名返回值优化
  • 复制省略

EDIT:我有意避免讨论NRVO不能被编译器应用的情况,原因是任何可以引用对象进行处理的函数f: void f( T & out ) { /* code */ }可以很容易地转换为NRVO对于编译器来说很容易实现的函数,通过简单的转换来返回值:T f() { T out; /* code */ return out; }

由于您的图像是大数据结构,我可能会建议函数应该返回指向图像的指针。您也可以使用引用(在机器级别是指针),但我认为指针更适合用于此目的。

我对C比c++更熟悉,所以我可能错了。

重要的问题是什么时候,由谁来取消分配。

至少,如果您的目标是针对Windows, MacOS, Linux或*BSD等典型操作系统的合理当前编译器,那么您可以很好地指望它们实现RVO/NRVO。现在,你必须非常努力地寻找有足够差异值得关注的案例——或者很可能根本没有任何差异。

取决于您如何使用所涉及的数据,如果存在速度差异,则可以像使用引用一样轻松地支持传递/返回对象。你可以读一读大卫·亚伯拉罕关于这方面的文章

看到"什么更快?"这个问题,我通常建议在编译器/环境中实际测量自己,然后找出原因。

相关文章: