C++ C+中的效率+;功能?
这可能是一个简单的问题,但我突然想到了这个问题。这是关于以下两个功能之间的差异:C++ C+中的效率+;功能?,c++,performance,C++,Performance,这可能是一个简单的问题,但我突然想到了这个问题。这是关于以下两个功能之间的差异: 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 outp
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\u one()
会比func\u two()
或func\u one()更有效吗
在返回两个对象的总和时,生成一个对象T
无论如何?编译器会将fund\u二优化为类似于func\u一的东西,然后再优化为其他东西,长话短说,你不必担心,除非你真的需要担心,在这种情况下,您可以查看asm输出。简短回答:我们不知道
详细答案:这在很大程度上取决于T的工作方式以及编译器对返回值优化的支持
任何按值返回的函数都可以应用RVO或NRVO优化。
这意味着它将直接将返回值构造到调用函数中,从而消除复制构造函数。由于这是按值返回大型对象的问题,这将意味着性能上的显著提高
func_one和func_two的区别在于func_one返回一个匿名临时值,即r值;这意味着RVO可以简单地使用。func_two返回一个命名值,一个l值,因此将使用NRVO,一个更难的优化。然而,func_二是微不足道的,因此几乎肯定会应用NRVO,并且两个函数基本相同
这是假设你有一个现代甚至半现代的编译器;如果不是,这将在很大程度上取决于您如何实现T
如果T具有移动语义,编译器将能够移动而不是复制。这应该适用于这两个职能,因为两者都存在临时性;但是,由于func_two返回一个命名值,它可能无法使用移动语义。这取决于编译器,如果编译器没有执行RVO或NRVO,我怀疑它是否在执行move
最后,它取决于+运算符和=运算符的实现方式。例如,如果它们被实现为表达式模板,那么fun_-two仍然需要赋值,这会减慢它的速度,而as-func_-one只会返回一个高度优化的临时值
总之
在几乎所有的实际情况下,这些都是相同的。在编译器行为异常的小窗口中,func_one的速度几乎普遍更快 现代编译器可以将带有额外变量的版本转换为不带变量的版本(例如,名为返回值优化,这是这里经常出现的问题)。所以这不是你应该担心的开销 您应该担心的开销是函数调用开销。一次加法最多只需要一个周期。函数调用需要10到20个周期,这取决于参数的数量 我有点不确定您在问题中使用
T
的意思(它是模板参数吗?它是类吗?它是您不想在问题中透露的类型的占位符吗?)。但是,是否存在函数调用开销问题取决于该类型。这取决于编译器是否可以内联函数
- 显然,如果它是内联的,您就可以了,没有函数调用开销
- 如果
是一个复杂类型,并且有一个昂贵的T
重载,那么您也可以操作符+()
- 但是,例如,如果
是T
,并且您的函数没有内联,那么您的函数大约有90%的开销int