C ++函数的效率?

时间:2013-11-26 02:25:22

标签: 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 output;
}

func_one()中,不是创建对象T,而是为其赋值,然后返回对象,我只返回值本身而不创建新对象。如果T是一个大型对象,那么当{2}}返回两个对象的总和时,func_one()会比func_two()更高效,或func_one()生成一个对象T

3 个答案:

答案 0 :(得分:0)

编译器会将fund_two优化为类似于func_one的东西,然后将其优化为其他东西,长话短说,你不必担心这个,除非你真的需要担心这个,那么在那种情况下你可以查看asm输出。

答案 1 :(得分:0)

简短回答:我们无法知道

答案很长:这在很大程度上取决于T的工作原理以及编译器是否支持返回值优化。

任何按值返回的函数都可以应用RVO或NRVO优化。 这意味着它将直接构造返回值到调用函数中,从而消除了复制构造函数。由于这是按值返回大型对象的问题,这将意味着性能的显着提升。

func_one和func_two之间的区别在于func_one返回一个匿名临时值,一个r值;这意味着可以轻松使用RVO。 func_two返回一个命名值,一个l值,因此将使用更难的优化NRVO。但是,func_two是微不足道的,因此它几乎肯定会应用NRVO,并且两个函数基本相同。

这假设你有一个现代甚至半现代的编译器;如果没有,它将在很大程度上取决于你如何实现T。

如果T具有移动语义,则编译器将能够移动而不是复制。这适用于两种功能,因为两者都存在临时性;但是,由于func_two返回一个命名值,它可能无法使用移动语义。这取决于编译器,如果编译器没有执行RVO或NRVO,我怀疑它是在做什么。

最后,它取决于如何实现+运算符和=运算符。例如,如果它们被实现为表达式模板,那么fun_two仍然需要一个赋值,这会降低它的速度,而func_one只会返回一个高度优化的临时值。

摘要 在几乎所有实际情况中,这些都是相同的。在编译器非常奇怪的小窗口中,func_one几乎普遍更快。

答案 2 :(得分:0)

现代编译器可以将带有额外变量的版本转换为没有的版本(命名返回值优化,这是SO上常见的问题来源,例如Why isn't the copy-constructor called when returning LOCAL variable)。所以这不是你应该担心的开销。

您应该担心的开销是函数调用开销。添加需要一个现代CPU,最多只需一个周期。函数调用需要10到20个周期,具体取决于参数的数量。

我有点不确定你在问题中对T的意思(它是一个模板参数吗?它是一个类吗?它是你不想在你的问题中披露的类型的占位符吗? ?)。但是,您是否有函数调用开销问题的问题取决于该类型。这取决于你的编译器是否可以内联你的函数。

  • 显然,如果它是内联的,你很好,没有函数调用开销。
  • 如果T是一个复杂的类型,并且过载费用很高operator+(),那么您也可以。
  • 但是,如果Tint,并且您的函数未内联,那么您的函数的开销大约为90%。