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
    int
    ,并且您的函数没有内联,那么您的函数大约有90%的开销

您不应该像这样添加和返回大型对象。任何现代优化编译器都会为这两者生成类似的程序集。此外,对于RVO和move语义,这可能是实现这一点最有效的方法。唯一知道的方法,就是剖析。