Разберём по полочкам преимущества и недостатки использования inline функций, в место макросов.
Благодаря использованию inline функций можно избежать многих недостатков присущих макросам. Например, возьмём один из самых распространённых макросов.
1 |
#define MAX( a, b ) ( (a) > (b) : (a) : (b) ) |
А теперь взглянем что произойдёт если его вызвать вот таким образом:
1 2 3 4 |
int x = 10; int y = 5; int result = MAX( ++x, y ); |
Что мы получим в итоге? А получим мы в переменной result значение равное 12! Явно не то число что мы ожидали. В случае с inline функцией такого естественно не будет, т.к. есть гарантия со стороны стандарта, что все вычисления будут произведены только один раз. Это и есть одна из проблем макросов. То, что мы в него передаём может отрабатываться не один и не два раза.
Рассмотрим еще один пример достаточно популярного макроса:
1 |
#define SQUARE( a ) ( a * a ) |
Если мы вызовем макрос с параметром 2 + 1. Результат опять же будет совсем не тот что мы ожидаем. А именно 5. Но никак не 9. Получаем мы это потому, что приоритет операции умножения, выше чем у операции сложения.
Ну и еще один fail макросов. Достаточно популярная в gamedev операция clamp:
1 2 3 |
#define CLAMP( a ) if( a > 1.0 ) a = 1.0; if( a < 0.0 ) a = 0.0; |
И предположим нам понадобилось вызвать её в цикле для набора значений:
1 2 |
for( int i = 0; i < n; i++ ) CLAMP( numbers[i] ); |
В этом случае у нас обрежутся только значения, которые больше 1.0 т. к. когда макрос будет раскрыт, то его вторая строчка попадёт за пределы цикла. Более того программа еще и упадёт после прохода цикла.
В общем, я исключительно за inline функции, пора уходить от С-шного наследия. Кто то скажет что Inline функции могут и не раскрыться компилятором и это приведёт к более медленной работе системы. Конечно может, но для этого у программиста есть такой инструмент как __forceinline. Ну и вообще лучше потратить время на оптимизацию программы где либо в другом месте, чем долго и усердно ловить баг, который может проявиться при использовании макросов.