Урок 101. Встроенные функции

   | 

   | 

 Обновлено 22 Дек 2017  | 

 3641

Использование функций дает много преимуществ, в том числе:

  код внутри функции может быть повторно использован;

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

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

  в функциях поддерживается проверка типов данных для гарантии того, что передаваемые аргументы соответствуют параметрам функции;

  функции упрощают отладку вашей программы.

Однако одним из главных недостатков использования функций является то, что каждый раз, когда она вызывается, происходит расход ресурсов, что влияет на производительность программы. Это связано с тем, что ЦП должен хранить адрес текущей команды (инструкции или стейтмента), которую он выполняет (чтобы знать, куда нужно будет вернуться позже) вместе с другими данными. Затем точка выполнения перемещается в другое место программы. Дальше все параметры функции должны быть созданы и им должны быть присвоены значения. И только потом, после выполнения функции, точка выполнения возвращается обратно. Код, написанный на месте, выполняется значительно быстрее.

Для функций, которые являются большими и/или выполняют сложные задачи, расходы на вызов обычно незначительны по сравнению с количеством времени, которое отводится на выполнение кода этой функции. Однако для небольших, часто используемых функций, время, необходимое для выполнения вызова, часто превышает время, необходимое для фактического выполнения кода этой функции. А это в свою очередь может привести к существенному снижению производительности.

C++ предлагает способ сочетания преимуществ функций со скоростью кода, написанного на месте: встроенные функции. Ключевое слово inline используется для запроса, чтобы компилятор рассматривал вашу функцию как встроенную. При компиляции вашего кода, все встроенные функции раскрываются на месте, то есть вызов функции заменяется копией содержимого самой функции, и ресурсы, которые могли бы быть потрачены на вызов этой функции, сохраняются! Минусом является лишь увеличение компилируемого кода за счет того, что встроенная функция раскрывается в коде при каждом вызове (особенно если она длинная и/или её вызывают много раз).



Рассмотрим следующий фрагмент кода:

Эта программа дважды вызывает функцию max(), т.е. дважды расходуются ресурсы на вызов функции. Поскольку max() является довольно таки короткой, то это идеальный кандидат для конвертации во встроенную функцию:

Теперь, при компиляции main(), ЦП будет читать этот код так, как если бы он был бы следующим:

Такой код выполниться быстрее, но цена — несколько увеличенный объем.

Из-за возможности подобного «раздувания», встроенные функции лучше всего использовать только для коротких функций (не более нескольких строк), которые обычно вызываются внутри циклов и не имеют ветвлений. Также обратите внимание, ключевое слово inline является только рекомендацией — компилятор может игнорировать ваш запрос на встроенную функцию. Подобное произойдет, если вы попытаетесь сделать встроенной длинную функцию!

Наконец, современные компиляторы автоматически конвертируют соответствующие функции во встроенные – этот процесс автоматизирован настолько, что даже лучше ручной выборочной конвертации программистом. Даже если вы не отметите функцию как встроенную, компилятор автоматически выполнит её как таковую, если посчитает, что это способствует производительности. Таким образом, в большинстве случаев нет особой необходимости использовать ключевое слово inline. Компилятор всё сделает сам.

Правило: Если вы используете современный компилятор, то нет необходимости использовать ключевое слово inline.

Встроенные функции освобождаются от правила одного определения

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

Однако встроенные функции освобождаются от этого правила, так как дублирования в исходном коде нет — определение функции одно, и никакого конфликта при соединении линкером файлов .cpp возникнуть не должно.

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

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

Оценить статью:

Звёзд: 1Звёзд: 2Звёзд: 3Звёзд: 4Звёзд: 5 (32 оценок, среднее: 4,91 из 5)
Загрузка...
Подписаться на обновления:

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

ВОЛШЕБНАЯ ТАБЛЕТКА ПО С++