这可能是一个简单的问题,但这是我的想法。这是关于以下两个函数之间的差异:
T func_one(T obj) { //for the purpose of this question,
return obj + obj; //T is a large object and has an overloaded '+' operator
}
T func_two(T obj) {
T output = obj + obj;
return output;
}在func_one()中,我不需要创建一个对象T,给它赋值,然后返回对象,只需要返回值本身,而不创建新对象。如果T是一个大对象,当返回两个对象的总和时,func_one()是否会比func_two()更有效,或者func_one()会不会让对象变成T?
发布于 2013-11-26 10:27:49
编译器会将fund_two优化成类似于func_one的东西,然后再优化成其他东西,长话短说,你不需要担心这个,除非你真的需要担心这个,在这种情况下,你可以查看asm的输出。
发布于 2013-12-30 18:49:50
Short answer:我们无法知道
Long answer:这在很大程度上取决于T的工作方式以及您的编译器对返回值优化的支持。
任何按值返回的函数都可以应用RVO或NRVO优化。这意味着它将直接将返回值构造到调用函数中,省去了复制构造函数。由于这是按值返回大对象的问题,这将意味着性能的大幅提高。
func_one和func_two之间的不同之处在于,func_one返回一个匿名临时值,即一个r值;这意味着可以很容易地使用RVO。func_two返回一个命名值,一个l值,因此将使用NRVO,这是一种更难的优化。然而,func_two是微不足道的,所以它几乎肯定会应用NRVO,并且这两个函数基本上是相同的。
这是假设你有一个现代甚至半现代的编译器;如果没有,这将在很大程度上取决于你如何实现T。
如果T具有移动语义,那么您的编译器将能够移动而不是复制。这应该适用于这两个函数,因为这两个函数中都存在临时函数;但是,由于func_two返回一个命名值,因此它可能无法使用移动语义。这取决于编译器,如果编译器不执行RVO或NRVO,我怀疑它是否在执行move。
最后,这取决于如何实现+运算符和=运算符。例如,如果它们是作为表达式模板实现的,那么fun_two仍然需要赋值,这会减慢它的速度,而as func_one将只返回一个高度优化的临时变量。
摘要中的在几乎所有的实际环境中,这些都是相同的。在编译器行为非常奇怪的小窗口中,func_one几乎普遍更快。
发布于 2013-12-30 19:15:56
现代编译器可以将有额外变量的版本转换为没有额外变量的版本(名为返回值优化,这在这里是一个相当常见的问题来源,例如Why isn't the copy-constructor called when returning LOCAL variable )。所以这不是你应该担心的开销。
你应该担心的开销是函数调用的开销。一个加法最多只需要一个现代CPU一个周期。函数调用需要10到20个周期,具体取决于参数的数量。
我有点不确定你的问题中的T是什么意思(它是一个模板参数吗?它是一个类吗?它是否是您不想在问题中透露的类型的占位符?)但是,是否存在函数调用开销问题取决于该类型。这取决于你的编译器是否能内联你的函数。
T是具有开销很大的operator+()重载的复杂类型,那么您也很好。但是,T是<代码>D11,而您的函数没有内联,则函数中大约有90%的开销。<代码>H212<代码>F213https://stackoverflow.com/questions/20207397
复制相似问题