ОБЪЕКТНО-ОРИЕНТИРОВАННОЕ ПРОГРАММИРОВАНИЕ В C++ (4-Е ИЗДАНИЕ) (часть 5) онлайн

Встраиваемые функции

Мы уже упоминали, что использование функций является экономичным с точки зрения использования памяти, поскольку вместо дублирования кода использует- ся механизм вызовов функций. Когда компилятор встречает вызов функции, он генерирует команду перехода в эту функцию. После выполнения функции осу- ществляется переход на оператор, следующий за вызовом функции, как было по- казано на рис. 5.1.

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

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

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

main()

main()

а) Повторяющийся код              б) Повторяющийся код

помещен в функцию   в программе

Рис. 5.9. Обычные функции против встраиваемых

 

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

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

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

Встраиваемыми следует делать только очень короткие функции, содержа- щие один-два оператора. Мы приведем небольшую модификацию программы CONVERT2 под названием INLINE, в которой функция lbstokg() сделана встраиваемой.

// inline.cpp

// применение встроенных функций #include  <iostream> using namespace std; // функция lbstokg() // переводит фунты в килограммы

inline float lbstokg(float pounds) {

  return 0.453592*pounds;

}

//--------------------------------------------------------

int main() {

float lbs;

cout << "\nВведите вес в фунтах: "; cin >> lbs;

cout << " " << lbstokg(lbs) << endl; return 0;

}

 

Для того чтобы сделать функцию встраиваемой, необходимо лишь указать ключевое слово inline в прототипе функции:

inline float lbstokg(float pounds)

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

Если вы знакомы с языком C, то вы отметите, что встраиваемые функции являются аналогом широко используемого в языке C макроса #define. Преиму- ществом встраиваемых функций по сравнению с макросами является их более корректная работа с типами данных, а также удобный синтаксис.

 

27