- •Содержание
- •Благодарности
- •Как читать эту книгу
- •Несколько слов о стиле программирования
- •Переменные и константы
- •const
- •Стековые и динамические объекты
- •Области действия и функции
- •Области действия
- •Перегрузка
- •Видимость
- •Типы и операторы
- •Конструкторы
- •Деструкторы
- •Присваивание
- •Перегрузка операторов
- •Что такое шаблоны и зачем они нужны?
- •Проблемы
- •Обходные решения
- •Синтаксис шаблонов
- •Параметризованные типы
- •Параметризованные функции
- •Параметризованные функции классов
- •Передача параметра
- •Шаблоны с несколькими параметрами
- •Долой вложенные параметризованные типы!
- •Наследование
- •Комбинации простых и параметризованных типов
- •Небезопасные типы в открытых базовых классах
- •Небезопасные типы в закрытых базовых классах
- •Небезопасные типы в переменных класса
- •Глава 4. Исключения
- •Обработка исключений в стандарте ANSI
- •Синтаксис инициирования исключений
- •Синтаксис перехвата исключений
- •Конструкторы и деструкторы
- •Нестандартная обработка исключений
- •Условные обозначения
- •Глава 5. Умные указатели
- •Глупые указатели
- •Умные указатели как идиома
- •Оператор ->
- •Параметризованные умные указатели
- •Иерархия умных указателей
- •Арифметические операции с указателями
- •Во что обходится умный указатель?
- •Применения
- •Разыменование значения NULL
- •Отладка и трассировка
- •Кэширование
- •Семантика ведущих указателей
- •Конструирование
- •Уничтожение
- •Копирование
- •Присваивание
- •Прототип шаблона ведущего указателя
- •Дескрипторы в C++
- •Что же получается?
- •Подсчет объектов
- •Указатели только для чтения
- •Указатели для чтения/записи
- •Интерфейсные указатели
- •Дублирование интерфейса
- •Маскировка указываемого объекта
- •Изменение интерфейса
- •Грани
- •Преобразование указываемого объекта в грань
- •Кристаллы
- •Вариации на тему граней
- •Инкапсуляция указываемого объекта
- •Проверка граней
- •Обеспечение согласованности
- •Грани и ведущие указатели
- •Переходные типы
- •Полиморфные указываемые объекты
- •Выбор типа указываемого объекта во время конструирования
- •Изменение указываемого объекта во время выполнения программы
- •Посредники
- •Функторы
- •Массивы и оператор []
- •Проверка границ и присваивание
- •Оператор [] с нецелыми аргументами
- •Имитация многомерных массивов
- •Множественные перегрузки оператора []
- •Виртуальный оператор []
- •Курсоры
- •Простой класс разреженного массива
- •Курсоры и разреженные массивы
- •Операторы преобразования и оператор ->
- •Итераторы
- •Активные итераторы
- •Пассивные итераторы
- •Что лучше?
- •Убогие, но распространенные варианты
- •Лучшие варианты
- •Итератор абстрактного массива
- •Операторы коллекций
- •Мудрые курсоры и надежность итераторов
- •Частные копии коллекций
- •Внутренние и внешние итераторы
- •Временная пометка
- •Пример
- •Тернистые пути дизайна
- •Транзакции
- •Отмена
- •Хватит?
- •Образы и указатели
- •Простой указатель образов
- •Стеки образов
- •Образы автоматических объектов
- •Образы указателей
- •Комбинации и вариации
- •Транзакции и отмена
- •Транзакции и блокировки
- •Класс ConstPtr
- •Класс LockPtr
- •Создание и уничтожение объектов
- •Упрощенное создание объектов
- •Отмена
- •Варианты
- •Вложенные блокировки
- •Взаимные блокировки и очереди
- •Многоуровневая отмена
- •Оптимизация объема
- •Несколько прощальных слов
- •Часть 3. Снова о типах
- •Гомоморфные иерархии классов
- •Взаимозаменяемость производных классов
- •Нормальное наследование
- •Инкапсуляция производных классов
- •Множественная передача
- •Двойная передача
- •Гетероморфная двойная передача
- •Передача более высокого порядка
- •Группировка передач и преобразования
- •Производящие функции
- •make-функции
- •Символические классы и перегруженные make-функции
- •Оптимизация с применением производящих функций
- •Локализованное использование производящих функций
- •Уничтожающие функции
- •Снова о двойной передаче: промежуточные базовые классы
- •Объекты классов
- •Информация о классе
- •Еще несколько слов об уничтожающих функциях
- •Определение класса по объекту
- •Представители
- •Основные концепции
- •Инкапсуляция указателей и указываемых объектов
- •Производящие функции
- •Ссылки на указатели
- •Неведущие указатели
- •Ведущие указатели
- •Снова о двойной передаче
- •Удвоенная двойная передача
- •Самомодификация и переходимость
- •Множественная двойная передача
- •Применение невидимых указателей
- •Кэширование
- •Распределенные объекты и посредники
- •Нетривиальные распределенные архитектуры
- •Часть 4. Управление памятью
- •Перегрузка операторов new и delete
- •Простой список свободной памяти
- •Наследование операторов new и delete
- •Аргументы оператора new
- •Конструирование с разделением фаз
- •Уничтожение с разделением фаз
- •Кто управляет выделением памяти?
- •Глобальное управление
- •Выделение и освобождение памяти в классах
- •Объекты классов и производящие функции
- •Управление памятью под руководством клиента
- •Управление памятью с применением ведущих указателей
- •Перспективы
- •Строительные блоки
- •Поблочное освобождение памяти
- •Скрытая информация
- •Подсчет ссылок
- •Базовый класс с подсчетом ссылок
- •Ведущие указатели с подсчетом ссылок
- •Дескрипторы с подсчетом ссылок
- •Трудности подсчета ссылок
- •Подсчет ссылок и ведущие указатели
- •Деление по классам
- •Деление по размеру
- •Деление по средствам доступа
- •Пространства стека и кучи
- •Поиск указателей
- •Мама, откуда берутся указатели?
- •Поиск указателей
- •Дескрипторы, повсюду дескрипторы
- •Общее описание архитектуры
- •Ведущие указатели
- •Вариации
- •Оптимизация в особых ситуациях
- •Алгоритм Бейкера
- •Пространства объектов
- •Последовательное копирование
- •Внешние объекты
- •Алгоритм Бейкера: уход и кормление в C++
- •Уплотнение на месте
- •Базовый класс VoidPtr
- •Пул ведущих указателей
- •Итератор ведущих указателей
- •Алгоритм уплотнения
- •Оптимизация
- •Перспективы
- •Глава 16. Сборка мусора
- •Доступность
- •Периметр
- •Внутри периметра
- •Анализ экземпляров
- •Перебор графа объектов
- •Сборка мусора по алгоритму Бейкера
- •Шаблон слабого дескриптора
- •Шаблон сильного дескриптора
- •Итераторы ведущих указателей
- •Перебор указателей
- •Оптимизация
- •Внешние объекты
- •Множественные пространства
- •Сборка мусора и уплотнение на месте
- •Нужно ли вызывать деструкторы?
- •Только для профессиональных каскадеров
- •Организация памяти
- •Поиск периметра
- •Перебор внутри периметра
- •Сборка мусора
- •Последовательная сборка мусора
- •Итоговые перспективы
144
Конечно, это намного упростило бы жизнь, но назвать эти загадочные ограничения бесполезными нельзя — они дают знатокам С++ хорошую тему для разговоров на семинарах с коктейлями.
Раз уж речь зашла об ограничениях С++, упомяну еще об одном. Взгляните на приведенный выше код класса Foo. Работа некоторых его функций сводится к вызову одной и той же функции для всех переменных класса и в более общем случае — базовых классов. Скажем, Foo::Commit() просто вызывает Commit() для всех переменных. Весь повторяющийся код приходится писать вручную; в языке сильно не хватает макросредств, которые бы позволяли сказать: «Вызвать функцию Commit() для каждой переменной класса». Компилятор знает, как составить список такого рода (и использует его в конструкторах), но вам ни за что не скажет.
Образы указателей
У шабона AutoImage есть одно довольно занятное применение — им можно воспользоваться для создания образов *-указателя. В некоторых ситуациях не хочется создавать лишние копии указываемого объекта только чтобы следить за тем, на что ссылался указатель в прошлой жизни. Собственно, дело обстоит так каждый раз, когда указатель не является ведущим. Указатель также помогает следить за объектами, которые были созданы или уничтожены в процессе транзакции.
AutoImage<Foo*> f;
Теперь вы можете восстановить состояние указателя f в начале транзакции, в том числе и NULL. Тем не менее, существует веский довод в пользу создания специализированного шаблона для *-указателей — необходимость перегрузки оператора ->, чтобы указатель образов можно было использовать в левой части выражений (что-нибудь типа ptr->MemberOfPointer();). Для *-указателей AutoImage похож на глупые указатели, с которыми мы рассправились в начале главы 5. Следующий шаблон больше напоминает обычные умные (но не ведущие!) указатели.
template <class Type> class PtrImage { private:
Type* current; Type* image;
bool have_image; // Истина, если образ существует public:
PtrImage() : current(NULL), image(NULL), have_image(false) {} PtrImage(const PtrImage<Type>& pi)
: current(pi.current), image(NULL), have_image(false) {} PtrImage<Type>& operator=(const PtrImage<Type>& pi)
{
if (this != &pi)
current = pi.current; return *this;
}
PtrImage<Type>& operator=(Type* t) { current = t; return *this; }
operator Type*() { return current; }
Type* operator->() const { return current; } bool operator!() { return current == NULL; } void Snapshot()
{
image = current; have_image = true;
}
void Commit() { image = NULL; have_image = false; }