返回值或修改引用传递的参数是否更快?
Is it faster to return a value or modify a parameter passed by reference?
在我正在编写的程序中,我必须在函数之间传递大型数据结构(图像)。我需要我的代码在不同的操作系统上尽可能快(因此,我不能分析所有的测试用例)。我经常有这样的代码…
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。现在,你必须非常努力地寻找有足够差异值得关注的案例——或者很可能根本没有任何差异。
取决于您如何使用所涉及的数据,如果存在速度差异,则可以像使用引用一样轻松地支持传递/返回对象。你可以读一读大卫·亚伯拉罕关于这方面的文章
看到"什么更快?"这个问题,我通常建议在编译器/环境中实际测量自己,然后找出原因。
- 是否有C++编译器选项允许激进地删除所有函数调用,并将参数传递给具有空体的函数
- 是否可以对零模板参数进行模板专门化
- 函数作为模板参数,是否对返回类型强制约束
- visual是否可以在c++中创建一个接收无限数量相同类型(或至少相当数量)参数的函数
- 函数是否可以访问传递给main()的参数
- 在C++中,使用带有 std::optional 参数的函数<T>来表示可选参数是否有意义?
- 如何检查给定的参数是否为 cv::noArray()?
- 表达式 SFINAE:如何根据类型是否包含具有一个或多个参数的函数来选择模板版本
- 如果返回 -1,时间() 的参数是否被修改?
- 用于检查值是否为其任何参数的帮助程序函数
- 将类型声明为类型模板参数的模板参数的一部分是否合法?
- 模板化检查是否存在带有参数列表的类成员函数?
- 我如何知道作为参数的size_t在函数中是否有效?
- 是否可以在C++中有一个"generic"模板参数,该参数可以是非类型模板参数或类型?
- 是否可以就地构造一个固定大小的数组作为函数参数?
- C++方法是否可以根据传递给构造函数的参数具有不同的返回类型?
- 是否可以在运行时强制转换模板参数?
- 是否可以在不填充自己的参数的情况下将模板函数作为参数传递?
- 编译器是否强制根据模板参数计算表达式?
- C++中大多数/所有 setter 函数的参数是否应该写为常量引用?