Какая из 2 функций по скорости выполнения будет быстрее и почему?

Есть вот такие 2 функции:

1.

#include <iostream>
int ReturnIntX(int x) {
    if (x == 1) {
        return x;
    }
}
int main()
{
    int a = 1;
    int b = ReturnIntX(a);
}
 
#include <iostream>
int ReturnInt1(int x) {
    if (x == 1) {
        return 1;
    }
}
int main()
{
    int a = 1;
    int b = ReturnInt1(a);
}
 

Имеет ли вляиние на это предыдущий запуск/фоновые процессы?

Мне интересно узнать, что будет быстрее: возвращение переданного аргумента, или литеральное значение? Ведь если так подумать, что переменная x, хоть и пустая может иметь "вес", а если ещё и значения, то "вес" увеличивается

P.s.: Могли бы подсказать библиотеки для самостоятельной проверки?


Ответы (3 шт):

Автор решения: Stanislav Volodarskiy

Если функция ReturnIntX получает аргумент x не равный единице, выполнение функции завершится без возврата значения. Язык C++ считает такую ситуацию неопределённым поведением. Компилятор предполагает что программист не допускает неопределённого поведения. То есть, фактически компилятор предполагает что x всегда будет передан в функцию со значением равным единице. А тогда можно сделать оптимизацию и вернуть из функции единицу, а условный оператор удалить. Более того, можно удалить и вызов функции, так как результат её выполнения известен заранее. Что компилятор и делает: все вызовы функции в коде заменяются на литеральное значение - единицу.

Это верно для обоих вариантов функции и делает ваш вопрос бессодержательным: кода функции в программе нет, интересоваться скоростью её работы бессмысленно.

P.S. Скорость работы функции вообще условность. Вы можете измерять скорость работы программы целиком и по этой скорости делать вывод о "скорости функции". Но "скорость функции" в другой программе может проявиться по-другому. Требуется большой опыт чтобы определить надежно "скорость функции".

→ Ссылка
Автор решения: VladD

Современные компиляторы давно уже не компилируют ваш код построчно. Задача компилятора — найти самый эффективный код, который будет вести себя так же, как и ваш исходник.

Поскольку в вашем случае (отвлекаясь от UB) смысл обоих фрагментов одинаковый, то и компилироваться он будет одинаково. Как именно — зависит от конкретного компилятора, а также от целевой платформы.

Вот например, для интеловской платформы clang произвёл одинаковый код: https://godbolt.org/z/EPKqxKP75:

mov     eax, 1
cmp     edi, 1
je      .EXIT

Компилятор вообще имеет право менять ваш код как угодно, только бы результат был таким же (за вычетом UB). Вот тут он, например, свернул цикл в обычное умножение.


Если вы хотите оптимизировать код, то не стоит заботиться о подобных нанооптимизациях, компилятор умеет это делать намного лучше вас. Оптимизируйте алгоритмы и структуры данных, которые вы используете.

→ Ссылка
Автор решения: Swift - Friday Pie

В случае натягивания абстрактной совы на виртуальный глобус ответить на этот вопрос невозможно.

Например, в данном конкретном случае функция будет эквивалентна return 1; из-за неопределённого поведения, и, возможно, после подстановки вообще уйдет из кода, просто где-то в регистр запишется единица.

В теории все зависит от того как из вашего буквального значения (литерального?) получается итоговый объект и насколько это "дороже" копирования, и насколько возможно подстановка. в случае исправленного кода.

Однако насколько RVO быстрее копирования заранее сказать нельзя. Можно только гарантировать, что NRVO на аргументы функции не распространяется, поэтому в не-consteval контексте не-ссылочный аргумент всегда будет скопирован, а не создан "на месте".

Остальное могут сказать только замеры производительности или чтение кода, созданного компилятором для конкретной ситуации.

→ Ссылка