Эффективность в функции C ++?

0

Это, наверное, простой вопрос, но это натолкнулось на мои мысли. Речь идет о различии между двумя функциями ниже:

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 любом случае при возврате суммы двух объектов?

  • 0
    Вы не должны добавлять и возвращать большие объекты, как это.
  • 2
    Любой современный оптимизирующий компилятор сгенерирует аналогичную сборку для обоих. Кроме того, с RVO и семантикой перемещения это вполне может быть наиболее эффективным способом достижения этой цели. Единственный способ узнать, это в профиль.
Теги:
performance

3 ответа

0

Современные компиляторы могут преобразовать версию с дополнительной переменной в единицу без (названная оптимизация возвращаемого значения, это довольно частый источник вопросов здесь, на SO, почему не вызывает конструктор-копию при возврате LOCAL-переменной, например). Так что это не накладные расходы, о которых вы должны беспокоиться.

Накладные расходы, о которых вы должны беспокоиться, - это служебные вызовы функции. Добавление занимает современный процессор не более одного цикла. Вызов функции занимает от 10 до 20 циклов, в зависимости от количества аргументов.

Я немного сомневаюсь, что вы имеете в виду с T в своем вопросе (это параметр шаблона? Это класс?). Это заполнитель для типа, который вы не хотели раскрывать в своем вопросе?). Однако вопрос о том, есть ли у вас проблема с функцией вызова функции, зависит от этого типа. И это зависит от того, может ли ваш компилятор встроить вашу функцию.

  • Очевидно, что если он встроен, вы в порядке, никаких накладных расходов на функции нет.
  • Если T - сложный тип с дорогостоящей operator+(), то вы тоже прекрасны.
  • Однако, если T int, например, и ваша функция не включена, то у вас есть примерно 90% накладных расходов в вашей функции.
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, я сомневаюсь, что он делает ход.

Наконец, это зависит от того, как реализуется оператор + operator и =. Если, например, они были реализованы в виде шаблонов выражений, то fun_two все еще требует назначения, что замедлит его, когда func_one просто вернет очень оптимизированное временное.

В резюме Почти во всех практических контекстах они идентичны. В исчезающем маленьком окне, где ваш компилятор действует очень странно, func_one почти повсеместно быстрее.

0

Компилятор оптимизировал бы fund_two во что-то похожее на func_one, которое затем было бы оптимизировано для чего-то еще, короткое короткое, вам не нужно беспокоиться об этом, если вам действительно не нужно об этом беспокоиться, тогда в этом случае вы можете посмотреть на выход asm.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню