- •И. А. Андрианов, д. В. Кочкин, с. Ю. Ржеуцкая
- •Учебное пособие
- •Оглавление
- •1. Основы языка 8
- •1.2.2 Простые типы данных 13
- •6. Паттерны проектирования 159
- •7. Антипаттерны 211
- •2. Работа с памятью 73
- •3. Основы объектно-ориентированного программирования 87
- •4.Обработка исключений 114
- •5. Шаблонные функции и классы. Библиотека стандартных шаблонов 130
- •9. Методы отладки и оптимизации кода 242
- •1. Основы языка
- •1.1.2 Понятие проекта
- •1.2 Простые типы данных
- •1.2.1 Понятие типа
- •1.2.2 Простые типы данных
- •1.2.3 Внутреннее представление простых типов
- •1.2.4 Ключевое слово typedef. Тип size_t
- •1.3 Константы и переменные
- •1.3.1 Литералы
- •1. Числовые константы:
- •2. Символьные константы:
- •1.3.2 Переменные
- •1.3.3 Описание переменных
- •1.4. Выражения. Преобразование типов
- •1.4.1 Операнды и операции
- •1.4.2 Приоритет операций
- •1.4.3 Преобразование типов
- •1.5 Ветвления и циклы
- •1.5.2 Циклы
- •1.6 Массивы, строки
- •1.6.1 Основные понятия
- •1.6.2 Встроенные массивы
- •1.6.3 Cтроки. Обработка строк с завершающим нулём
- •1.7 Указатели и ссылки. Связь указателей и массивов. Библиотека cstring
- •1.7.1 Понятия указателя и ссылки
- •1.7.2 Связь между массивами и указателями
- •1.7.3 Библиотека cstring
- •1.8 Использование типов vector и string
- •1.8.1 Шаблонный класс vector
- •1.8.2 Класс string
- •1.9 Структуры и объединения. Битовые поля
- •1.10.1 Понятие функции
- •1.10.2 Описание функции и прототип функции
- •1.11 Параметры функции. Способы передачи параметров
- •1.11.1 Параметры функции и глобальные переменные
- •1.11.2 Способы передачи параметров в функцию
- •1.11.3 Передача массивов в функцию
- •1.11.4 Параметры-константы
- •1.11.5 Значения параметров по умолчанию
- •1.12.1 Указатель на функцию
- •1.12.2 Функции с переменным числом параметров
- •1.12.3 Перегрузка функций
- •1.12.4 Встроенные (inline) функции
- •1.13 Рекурсивные функции
- •1.14 Пространства имён
- •1.15 Директивы препроцессора. Макросы
- •2. Работа с памятью
- •2.1 Управление выделением и освобождением памяти
- •2.1.1 Статическое и динамическое выделение памяти
- •2.1.2 Способы динамического выделения и освобождения памяти
- •2.2 Динамические структуры данных
- •2.2.1 Основные понятия
- •2.2.2 Примеры реализации динамических структур на основе указателей
- •3. Основы объектно-ориентированного программирования
- •3.1 Основные понятия ооп
- •3.2.1 Описание класса
- •3.2.2 Область видимости элементов класса. Инкапсуляция
- •3.2.3 Первые примеры
- •3.3. Конструкторы и деструкторы.
- •3.4 Указатель this
- •3.5 Перегрузка операций
- •3.6 Дружественные функции и классы
- •3.7 Статические элементы класса
- •3.8 Наследование и полиморфизм
- •3.8.1. Основные понятия
- •3.8.2 Одиночное наследование
- •3.8.3 Множественное наследование
- •3.8.4 Конструкторы и деструкторы классов-потомков
- •3.9. Полиморфизм при наследовании классов
- •3.9.1 Механизмы раннего и позднего связывания
- •3.9.2 Абстрактные классы
- •4.Обработка исключений
- •4.1 Основные понятия
- •4.2 Перехват исключений
- •4.3 Поиск обработчика исключений. Раскрутка стека.
- •4.4 Повторное возбуждение исключений
- •4.5 "Аппаратные" и "программные" исключения
- •4.6 Стандартные классы исключений
- •4.7 Спецификация исключений, возбуждаемых функцией
- •4.8 Исключения в конструкторах при наследовании
- •4.9. Исключения в деструкторах
- •5. Шаблонные функции и классы. Библиотека стандартных шаблонов
- •5.1 Шаблонные функции
- •5.2 Шаблонные классы
- •5.3 Специализация шаблонов
- •5.4 Шаблонные параметры шаблонов
- •5.6 Использование шаблонов для вычислений на этапе компиляции
- •5.5 Разработка шаблонных классов с настраиваемой функциональностью
- •5.7 Библиотека стандартных шаблонов (stl) – основные понятия
- •5.8 Последовательные контейнеры. Итераторы
- •5.9. Адаптеры контейнеров
- •5.10 Ассоциативные контейнеры
- •5.11 Алгоритмы
- •6. Паттерны проектирования
- •6.1 Порождающие шаблоны
- •6.2 Структурные шаблоны
- •6.3 Шаблоны поведения
- •6.4 Шаблон "фабричный метод" (Factory method)
- •6.5 Шаблон "одиночка" (Singleton)
- •6.6 Шаблон "итератор" (Iterator)
- •6.7 Шаблон "наблюдатель" (Observer)
- •6.8 Шаблон "пул объектов" (Object pool)
- •6.9 Шаблон "команда" (Command)
- •6. 10 Шаблон "посетитель" (Visitor)
- •6.11 Дополнительные задания
- •6.11.1 Шаблон Iterator
- •6.11.2 Шаблон Observer
- •6.11.3 Шаблоны Command и Observer
- •6.11.5 Шаблон Visitor
- •6.11.5 Разработка класса − контейнера
- •6.11.6 Оценка производительности кода
- •7. Антипаттерны
- •7.1 Программирование методом копирования и вставки (Copy-Paste Programming)
- •7.2 Спагетти-код (Spaghetti code)
- •7.3 Магические числа (Magic numbers)
- •7.4 Бездумное комментирование
- •7.5 Жесткое кодирование (Hard code)
- •7.6 Мягкое кодирование (Soft code)
- •7.7 Золотой молоток (Golden hammer)
- •7.8 Слепая вера (Blind faith)
- •7.9 Ненужная сложность (Accidental complexity)
- •7.10 Божественный объект (God Object)
- •7.11 Лодочный якорь (Boat anchor)
- •7.12 Поток лавы (Lava flow)
- •7.13 Изобретение велосипеда (Reinventing the wheel)
- •7.14 Программирование перебором (Programming by permutation)
- •8.1 Выведение типов
- •8.2 Списки инициализации
- •8.3 Улучшение процесса инициализации объектов
- •8.4 Цикл for по коллекции
- •8.5 Лямбда-функции
- •8.6 Константа нулевого указателя nullptr
- •8.7 "Умные" указатели
- •9. Методы отладки и оптимизации кода
- •9.1 Отладка кода
- •9.1.1 Основные этапы отладки
- •9.1.2 Инструменты и приёмы отладки
- •9.2 Оптимизация кода
- •9.2.1 Рекомендации по выполнению оптимизации
- •9.2.2 Методики оптимизации кода
- •Заключение
- •Библиографический список
7.3 Магические числа (Magic numbers)
Магические числа − это числовые константы, встречающиеся в программном коде без наличия должных комментариев. Магические числа могут быть частью выражения, могут быть использованы при инициализации переменных или при передаче параметров в функцию. В большинстве случаев число не несет никакой информации о целях, для которых оно используется.
Причиной появления магических чисел в программе может быть спешка при кодировании, отсутствие опыта либо игнорирование стандартов кодирования.
Магические числа могут привести к множеству проблем в программе:
1. Использование в программе одного магического числа множество раз приводит к сложностям при необходимости изменения его значения. Например, значения числа пи в программе может быть задано константой 3.14, однако, если в определенный момент времени нас не устроит точность, потребуется указать новое значение − например, 3.14159. В случае, если одно или несколько значений останутся без изменений, в программе возникнут ошибки, которые будет очень сложно обнаружить.
2. Помимо необходимости изменения всех значений магического числа, может возникнуть проблема с разными по смыслу, но одинаковыми по значению магическими числами. Например, число 8 может обозначать как количество бит в байте, так и количество байт, занимаемых значением типа int в 64-х битной системе. Для того чтобы определить, какой смысл заложен в конкретное магическое число, потребуется дополнительное время для анализа контекста использования. Если при необходимости изменения магического числа ориентироваться только на его значение, это с большой вероятностью приведет к появлению ошибок.
3. Одно или несколько магических чисел из всего множества чисел, используемых в программе, может быть указано с ошибкой изначально.
4. Использование магических чисел может привести к проблемам с переносимостью программы по причине того, что размеры типов данных в 32-битной версии программы и в 64-битной версии будут отличаться. Например, такой код в 64-битной версии программы приведет к ошибке во время выполнения:
const size_t COUNT = 10;
int arr[COUNT];
memset(arr, 0, COUNT * 4);
Причина ошибки в том, что размер типа int жестко задан равным 4 байтам. Для исключения указанной ошибки можно изменить третью строчку следующим образом:
memset(arr, 0, COUNT * sizeof(arr[0]));
либо
memset(arr, 0, sizeof(arr));
Альтернативой магическим числам является использование именованных констант. Константы позволяют избежать проблем с модификацией значений магических чисел, а также упрощают понимание кода.
7.4 Бездумное комментирование
Для бездумного комментирования характерна ситуация, когда программный код снабжается большим количеством лишних комментариев, например:
// Пример 7.1 - пример бездумного комментирования
// Если а больше чем b
if(a>b) {}
// Увеличить переменную х на единицу
++x;
// Цикл for, в котором переменная увеличивается от 0 до 9 включительно
for(int i = 0; i != 10; ++i) {}
Данные комментарии не несут полезной нагрузки, а лишь раздувают размер программного кода и затрудняют его анализ. Другим примером антипаттерна могут быть различные шутки в комментариях или диалог разработчиков. Целью написания комментариев является облегчение процесса анализ кода.
Антипаттерн может являться следствием малого опыта командной разработки либо плохого знания конструкций языка программирования.
При написании комментариев следует следить за тем, чтобы они были информативными, поясняли принятые решения, описывали назначение функций, классов, допустимые значения и смысл параметров. Комментариев относительно конструкций языка программирования следует избегать.
