- Любовные романы
- Фантастика и фэнтези
- Ненаучная фантастика
- Ироническое фэнтези
- Научная Фантастика
- Фэнтези
- Ужасы и Мистика
- Боевая фантастика
- Альтернативная история
- Космическая фантастика
- Попаданцы
- Юмористическая фантастика
- Героическая фантастика
- Детективная фантастика
- Социально-психологическая
- Боевое фэнтези
- Русское фэнтези
- Киберпанк
- Романтическая фантастика
- Городская фантастика
- Технофэнтези
- Мистика
- Разная фантастика
- Иностранное фэнтези
- Историческое фэнтези
- LitRPG
- Эпическая фантастика
- Зарубежная фантастика
- Городское фентези
- Космоопера
- Разное фэнтези
- Книги магов
- Любовное фэнтези
- Постапокалипсис
- Бизнес
- Историческая фантастика
- Социально-философская фантастика
- Сказочная фантастика
- Стимпанк
- Романтическое фэнтези
- Ироническая фантастика
- Детективы и Триллеры
- Проза
- Юмор
- Феерия
- Новелла
- Русская классическая проза
- Современная проза
- Повести
- Контркультура
- Русская современная проза
- Историческая проза
- Проза
- Классическая проза
- Советская классическая проза
- О войне
- Зарубежная современная проза
- Рассказы
- Зарубежная классика
- Очерки
- Антисоветская литература
- Магический реализм
- Разное
- Сентиментальная проза
- Афоризмы
- Эссе
- Эпистолярная проза
- Семейный роман/Семейная сага
- Поэзия, Драматургия
- Приключения
- Детская литература
- Загадки
- Книга-игра
- Детская проза
- Детские приключения
- Сказка
- Прочая детская литература
- Детская фантастика
- Детские стихи
- Детская образовательная литература
- Детские остросюжетные
- Учебная литература
- Зарубежные детские книги
- Детский фольклор
- Буквари
- Книги для подростков
- Школьные учебники
- Внеклассное чтение
- Книги для дошкольников
- Детская познавательная и развивающая литература
- Детские детективы
- Домоводство, Дом и семья
- Юмор
- Документальные книги
- Бизнес
- Работа с клиентами
- Тайм-менеджмент
- Кадровый менеджмент
- Экономика
- Менеджмент и кадры
- Управление, подбор персонала
- О бизнесе популярно
- Интернет-бизнес
- Личные финансы
- Делопроизводство, офис
- Маркетинг, PR, реклама
- Поиск работы
- Бизнес
- Банковское дело
- Малый бизнес
- Ценные бумаги и инвестиции
- Краткое содержание
- Бухучет и аудит
- Ораторское искусство / риторика
- Корпоративная культура, бизнес
- Финансы
- Государственное и муниципальное управление
- Менеджмент
- Зарубежная деловая литература
- Продажи
- Переговоры
- Личная эффективность
- Торговля
- Научные и научно-популярные книги
- Биофизика
- География
- Экология
- Биохимия
- Рефераты
- Культурология
- Техническая литература
- История
- Психология
- Медицина
- Прочая научная литература
- Юриспруденция
- Биология
- Политика
- Литературоведение
- Религиоведение
- Научпоп
- Психология, личное
- Математика
- Психотерапия
- Социология
- Воспитание детей, педагогика
- Языкознание
- Беременность, ожидание детей
- Транспорт, военная техника
- Детская психология
- Науки: разное
- Педагогика
- Зарубежная психология
- Иностранные языки
- Филология
- Радиотехника
- Деловая литература
- Физика
- Альтернативная медицина
- Химия
- Государство и право
- Обществознание
- Образовательная литература
- Учебники
- Зоология
- Архитектура
- Науки о космосе
- Ботаника
- Астрология
- Ветеринария
- История Европы
- География
- Зарубежная публицистика
- О животных
- Шпаргалки
- Разная литература
- Зарубежная литература о культуре и искусстве
- Пословицы, поговорки
- Боевые искусства
- Прочее
- Периодические издания
- Фанфик
- Военное
- Цитаты из афоризмов
- Гиды, путеводители
- Литература 19 века
- Зарубежная образовательная литература
- Военная история
- Кино
- Современная литература
- Военная техника, оружие
- Культура и искусство
- Музыка, музыканты
- Газеты и журналы
- Современная зарубежная литература
- Визуальные искусства
- Отраслевые издания
- Шахматы
- Недвижимость
- Великолепные истории
- Музыка, танцы
- Авто и ПДД
- Изобразительное искусство, фотография
- Истории из жизни
- Готические новеллы
- Начинающие авторы
- Спецслужбы
- Подростковая литература
- Зарубежная прикладная литература
- Религия и духовность
- Старинная литература
- Справочная литература
- Компьютеры и Интернет
- Блог
Эффективное использование C++. 55 верных способов улучшить структуру и код ваших программ - Скотт Майерс
Шрифт:
Интервал:
Закладка:
Каждая конкретизация шаблона Factorial является структурой struct, и в каждой структуре используется «трюк с перечислением» (см. правило 2) для объявления переменной TMP с именем value. В переменной value хранится текущее значение факториала. Если бы в TMP были настоящие циклы, то значение value обновлялось бы на каждой итерации цикла. Но поскольку в TMP место циклов заменяет рекурсивная конкретизация шаблонов, то каждая конкретизация получает свою собственную копию value, и значение копии соответствует «итерации цикла».
Использовать Factorial можно следующим образом:
int main()
{
std::cout << Factorial<5>::value; // печатается 120
std::cout << Factorial<10>::value; // печатается 3628800
}
Если вы находите описанный прием элегантным, значит, вы стали на путь превращения в метапрограммиста шаблонов. Если же все эти шаблоны, специализации, рекурсивные конкретизации, трюк с перечислением и необходимость набирать нечто вроде Factorial<n-1>::value не вызывают у вас восторга, стало быть, вы вполне нормальный программист C++.
Конечно, шаблон Factorial в такой же мере демонстрирует полезность TMP, как «Hello World» – полезность любого обычного языка программирования. Чтобы понять, почему о TMP стоит знать, важно представлять себе, чего можно достичь с помощью этой технологии. Вот три примера:
• Обеспечение корректности единиц измерения. В научных и инженерных приложениях важно, чтобы единицы измерения (например, массы, расстояния, времени и т. п.) правильно сочетались. Присваивание переменной, представляющей массу, значения переменной, представляющей скорость, – это ошибка, но деление переменной расстояния на переменную времени и присваивание результата переменной скорости правильно. Используя TMP, можно обеспечить (во время компиляции), что все комбинации единиц измерения в программе будут корректны, независимо от того, насколько сложны вычисления. (Это пример того, как можно использовать TMP для ранней диагностики ошибок.) Одним интересным аспектом такого использования TMP может быть поддержка вычисления дробных степеней. Смысл в том, чтобы дроби сокращались во время компиляции, то есть чтобы компилятор мог подтвердить, например, что единица времени в степени 1/2 – это то же самое, что единица времени в степени 4/8.
• Оптимизация операций с матрицами. В правиле 21 объясняется, что некоторые функции, включая operator*, должны возвращать новые объекты, а в правиле 44 представлен класс SquareMatrix, поэтому рассмотрим такой код:
typedef SquareMatrix<double, 10000> BigMatrix;
BigMatrix m1, m2, m3, m4, m5; // создать матрицы
... // и присвоить им значения
BigMatrix result = m1 * m2 * m3 * m4 * m5; // вычислить произведение
Вычисление result «нормальным» способом приводит к созданию четырех временных матриц, по одной для каждого вызова operator*. Более того, независимые операции умножения порождают последовательность из четырех циклов по элементам матрицы. Но применение передовой шаблонной технологии, тесно связанной с TMP и получившей название шаблоны выражений (expression templates), позволяет избежать создания временных объектов и объединить циклы, причем все это без изменения приведенного выше пользовательского кода. В результате программа требует меньше памяти и выполняется значительно быстрее.
• Генерация специализированных реализаций паттернов проектирования. Паттерны проектирования, подобные Strategy (см. правило 35), Observer, Visitor и т. п., могут быть реализованы многими способами. Используя основанную на TMP технологию, называемую проектирование на основе политик (policy-based design), можно создавать шаблоны, представляющие независимые проектные решения («политики»), которые могут быть соответствующим образом скомбинированы для порождения реализаций паттернов с заданным поведением. Например, эта техника применялась для того, чтобы из нескольких шаблонов, реализующих различное поведение «интеллектуальных» указателей, породить (во время компиляции) любой из сотен разных типов «интеллектуальных» указателей. В результате обобщения, выходящего за рамки привычных программных конструкций, к примеру паттернов проектирования и «интеллектуальных» указателей, эта технология ложится в основу так называемого порождающего программирования (generative programming).
Технология TMP предназначена не для всех. Применяемый в ней синтаксис интуитивно не очевиден, а поддерживающий инструментарий не развит. (Отладчики для шаблонных метапрограмм? Ну насмешили, право!) Поскольку это вспомогательный язык, открытый сравнительно недавно, то применяемые в нем соглашения носят пока экспериментальный характер. Тем не менее повышение эффективности за счет переноса части со стадии исполнения на стадию компиляции может оказаться значительным, а возможность выразить поведение, которое трудно или невозможно реализовать во время исполнения, также весьма привлекательно.
Поддержка TMP растет. Вероятно, в следующей версии C++ будет реализована явная поддержка этой технологии, в TR1 это уже декларировано (см. правило 54). Начали появляться книги, посвященные этой теме, а информация о TMP в Internet становится все богаче. Видимо, TMP никогда не станет главным направлением развития, но для некоторых программистов (особенно разработчиков библиотек) она почти наверняка займет важное место.
Что следует помнить• Метапрограммирование шаблонов позволяет перенести часть работы со стадии исполнения на стадию компиляции. За счет этого можно раньше обнаружить ошибки и повысить производительность программ.
• Технология TMP может быть использована для генерации кода на основе комбинации политик, а также чтобы предотвратить генерацию кода, некорректного для определенных типов данных.
Глава 8
Настройка new и delete
В наши дни, когда вычислительные среды снабжены встроенной поддержкой «сборки мусора» (как, например, Java и. NET), ручной подход C++ к управлению памятью может показаться несколько устаревшим. Однако многие разработчики, создающие требовательные к ресурсам прикладные программы, выбирают C++ именно потому, что он позволяет управлять памятью вручную. Такие разработчики изучают, как используется память в их программах, и разрабатывают собственные процедуры распределения и освобождения памяти с целью достичь максимально возможной производительности (с точки зрения как времени, так и потребления памяти) своих систем.
Для этого нужно понимать, как организованы процедуры управления памятью в C++. Именно этой теме и посвящена настоящая глава. Два основных компонента здесь – это процедура выделения и освобождения памяти (операторы new и delete), а вспомогательная роль отводится обработчику new – функции, которая вызывается, когда new не может удовлетворить запрос на выделение памяти.
С управлением памятью в многопоточной среде связаны дополнительные сложности, не возникающие в однопоточных системах, поскольку «куча» – это модифицируемый глобальный ресурс, доступ к которому должен быть синхронизирован. Во многих правилах из настоящей главы идет речь об использовании модифицируемых статических данных. Эта тема всегда настораживает программистов, разрабатывающих многопоточные программы. Без правильной синхронизации, отсутствия взаимных блокировок в алгоритмах и тщательного проектирования с целью предотвращения одновременного доступа, обращения к процедурам работы с памятью могут легко привести к повреждению структур данных, управляющих кучей. Вместо того чтобы постоянно напоминать вам об этой опасности, я говорю об этом только здесь и предполагаю, что вы будете помнить об этом при чтении остальной части главы.
Следует помнить и о том, что операторы new и delete применимы только к выделению и освобождению одиночных объектов. Память для массивов выделяет operator new[] и освобождает operator delete[] (в обоих случаях «[]» является частью имен функций). Если явно не оговорено противное, то все сказанное об операторах new и delete касается также new[] и delete[].
И наконец, отмечу, что в случае STL-контейнеров выделением памяти из кучи управляют объекты-распределители, ассоциированные с самими контейнерами, а не напрямую new и delete. В этой главе ничего не говорится о распределителях памяти в STL.
Правило 49: Разберитесь в поведении обработчика new
Когда оператор new не может удовлетворить запрос на выделение памяти, он возбуждает исключение. Когда-то он возвращал нулевой указатель, и некоторые старые компиляторы все еще так и поступают. Вы можете столкнуться с таким устаревшим поведением, но я отложу его обсуждение до конца правила.
Прежде чем возбудить исключение в ответ на невозможность удовлетворить запрос на выделение памяти, оператор new вызывает определенную пользователем функцию, называемую обработчиком new (new-handler). (На самом деле это не совсем так. Реальное поведение new несколько сложнее. Подробности описаны в правиле 51.) Чтобы задать функцию, обрабатывающую нехватку памяти, клиенты вызывают set_new_handler – стандартную библиотечную функцию, объявленную в заголовочном файле <new>:

