264 _______________Часть II. Программирование на C++
Существуют приемы, призванные избавиться от рекурсии. Обычными для исключения рекурсии являются циклы. Часто целесообразно бывает решить проблему рекурсивным путем, а позже, убедившись, что все работает правильно, рекурсию убрать.
Вот пример вычисления факториала, из которого рекурсия исключена с помощью цикла for.
unsigned long Factorial( unsigned long n) {
assert( n <= 12); // 13! " б.х 1012 — слишком много
unsigned long result = 1;
for (; n > 2; n—)
result *= n;
return result;
} ' '.
В этих вычислениях стек не участвует, и функция, наверное, работает чуть побыстрее. Попробуйте ради интереса с помощью объекта Timer собрать статистику и выяснить, какая же из функций на самом деле быстрее. Разница, скорее всего, составит микросекунды.
Несколько слов о перегрузке
Сейчас мы не станем детально вдаваться в рассмотрение перегрузки функций; эта тема достаточно важна, чтобы уделить ей отдельную главу. В свое время для уменьшения количества имен функций и, соответственно, облегчения труда программистов, были придуманы списки аргументов переменной длины. Но использование таких списков существенно сказывается на времени выполнения функций.
Создание множества семантически похожих функций с разными именами является непроизводительной тратой времени. В главе 15 "Перегрузка функций" и в главе 16 "Перегрузка операций" рассказывается о реализованном в C++ механизме поддержки перегрузки на основе имен и типов аргументов. В результате отпадает необходимость в списках аргументов переменной длины и запоминании множества имен функций, созданных только для того, чтобы производить одинаковые операции, но с разными типами данных.
Функторы
Функторы (functors) — это еще один инструмент, который вам стоит иметь в своей мастерской. Некоторые полагают, что функторы слишком заумная вещь, но при ближайшем рассмотрении вы убедитесь, что это не так.