- Любовные романы
- Фантастика и фэнтези
- Ненаучная фантастика
- Ироническое фэнтези
- Научная Фантастика
- Фэнтези
- Ужасы и Мистика
- Боевая фантастика
- Альтернативная история
- Космическая фантастика
- Попаданцы
- Юмористическая фантастика
- Героическая фантастика
- Детективная фантастика
- Социально-психологическая
- Боевое фэнтези
- Русское фэнтези
- Киберпанк
- Романтическая фантастика
- Городская фантастика
- Технофэнтези
- Мистика
- Разная фантастика
- Иностранное фэнтези
- Историческое фэнтези
- LitRPG
- Эпическая фантастика
- Зарубежная фантастика
- Городское фентези
- Космоопера
- Разное фэнтези
- Книги магов
- Любовное фэнтези
- Постапокалипсис
- Бизнес
- Историческая фантастика
- Социально-философская фантастика
- Сказочная фантастика
- Стимпанк
- Романтическое фэнтези
- Ироническая фантастика
- Детективы и Триллеры
- Проза
- Юмор
- Феерия
- Новелла
- Русская классическая проза
- Современная проза
- Повести
- Контркультура
- Русская современная проза
- Историческая проза
- Проза
- Классическая проза
- Советская классическая проза
- О войне
- Зарубежная современная проза
- Рассказы
- Зарубежная классика
- Очерки
- Антисоветская литература
- Магический реализм
- Разное
- Сентиментальная проза
- Афоризмы
- Эссе
- Эпистолярная проза
- Семейный роман/Семейная сага
- Поэзия, Драматургия
- Приключения
- Детская литература
- Загадки
- Книга-игра
- Детская проза
- Детские приключения
- Сказка
- Прочая детская литература
- Детская фантастика
- Детские стихи
- Детская образовательная литература
- Детские остросюжетные
- Учебная литература
- Зарубежные детские книги
- Детский фольклор
- Буквари
- Книги для подростков
- Школьные учебники
- Внеклассное чтение
- Книги для дошкольников
- Детская познавательная и развивающая литература
- Детские детективы
- Домоводство, Дом и семья
- Юмор
- Документальные книги
- Бизнес
- Работа с клиентами
- Тайм-менеджмент
- Кадровый менеджмент
- Экономика
- Менеджмент и кадры
- Управление, подбор персонала
- О бизнесе популярно
- Интернет-бизнес
- Личные финансы
- Делопроизводство, офис
- Маркетинг, PR, реклама
- Поиск работы
- Бизнес
- Банковское дело
- Малый бизнес
- Ценные бумаги и инвестиции
- Краткое содержание
- Бухучет и аудит
- Ораторское искусство / риторика
- Корпоративная культура, бизнес
- Финансы
- Государственное и муниципальное управление
- Менеджмент
- Зарубежная деловая литература
- Продажи
- Переговоры
- Личная эффективность
- Торговля
- Научные и научно-популярные книги
- Биофизика
- География
- Экология
- Биохимия
- Рефераты
- Культурология
- Техническая литература
- История
- Психология
- Медицина
- Прочая научная литература
- Юриспруденция
- Биология
- Политика
- Литературоведение
- Религиоведение
- Научпоп
- Психология, личное
- Математика
- Психотерапия
- Социология
- Воспитание детей, педагогика
- Языкознание
- Беременность, ожидание детей
- Транспорт, военная техника
- Детская психология
- Науки: разное
- Педагогика
- Зарубежная психология
- Иностранные языки
- Филология
- Радиотехника
- Деловая литература
- Физика
- Альтернативная медицина
- Химия
- Государство и право
- Обществознание
- Образовательная литература
- Учебники
- Зоология
- Архитектура
- Науки о космосе
- Ботаника
- Астрология
- Ветеринария
- История Европы
- География
- Зарубежная публицистика
- О животных
- Шпаргалки
- Разная литература
- Зарубежная литература о культуре и искусстве
- Пословицы, поговорки
- Боевые искусства
- Прочее
- Периодические издания
- Фанфик
- Военное
- Цитаты из афоризмов
- Гиды, путеводители
- Литература 19 века
- Зарубежная образовательная литература
- Военная история
- Кино
- Современная литература
- Военная техника, оружие
- Культура и искусство
- Музыка, музыканты
- Газеты и журналы
- Современная зарубежная литература
- Визуальные искусства
- Отраслевые издания
- Шахматы
- Недвижимость
- Великолепные истории
- Музыка, танцы
- Авто и ПДД
- Изобразительное искусство, фотография
- Истории из жизни
- Готические новеллы
- Начинающие авторы
- Спецслужбы
- Подростковая литература
- Зарубежная прикладная литература
- Религия и духовность
- Старинная литература
- Справочная литература
- Компьютеры и Интернет
- Блог
Язык программирования C++. Пятое издание - Стенли Липпман
Шрифт:
Интервал:
Закладка:
Определять все эти функции не обязательно: вполне можно определить один или два из них, не определяя все. Эти функции можно считать модулями. Если нужен один, не обязательно определять их все.
Классы, нуждающиеся в деструкторах, нуждаются в копировании и присвоенииВот эмпирическое правило, используемое при принятии решения о необходимости определения в классе собственных версий функций-членов управления копированием: сначала следует решить, нужен ли классу деструктор. Зачастую потребность в деструкторе более очевидна, чем потребность в операторе присвоения или конструкторе копий. Если класс нуждается в деструкторе, он почти наверняка нуждается также в конструкторе копий и операторе присвоения копии.
Используемый в упражнениях класс HasPtr отлично подойдет для примера (см. раздел 13.1.1). Этот класс резервирует динамическую память в конструкторе. Синтезируемый деструктор не будет удалять указатель-член. Поэтому данный класс должен определить деструктор для освобождения памяти, зарезервированной конструктором.
Хоть это и не очевидно, но согласно эмпирическому правилу класс HasPtr нуждается также в конструкторе копий и операторе присвоения копии.
Давайте посмотрим, что было бы, если бы у класса HasPtr был деструктор и синтезируемые версии конструктора копий и оператора присвоения копии:
class HasPtr {
public:
HasPtr(const std::string &s = std::string()):
ps(new std::string(s)), i(0) { }
~HasPtr() { delete ps; }
// ошибка: HasPtr нуждается в конструкторе копий и операторе
// присвоения копии
// другие члены, как прежде
};
В этой версии класса зарезервированная в конструкторе память будет освобождена при удалении объекта класса HasPtr. К сожалению, здесь есть серьезная ошибка! Данная версия класса использует синтезируемые версии операторов копирования и присвоения. Эти функции копируют указатели-члены, а значит, несколько объектов класса HasPtr смогут указывать на ту же область памяти:
HasPtr f(HasPtr hp) // HasPtr передан по значению, поэтому он
// копируется
{
HasPtr ret = hp; // копирует данный HasPtr
// обработка ret
return ret; // ret и hp удаляются
}
Когда функция f() завершает работу, объекты hp и ret удаляются и деструктор класса HasPtr выполняется для каждого из них. Этот деструктор удалит указатель-член и в объекте ret, и в объекте hp. Но эти объекты содержат одинаковое значение указателя. Код удалит тот же указатель дважды, что является серьезной ошибкой (см. раздел 12.1.2) с непредсказуемыми результатами.
Кроме того, вызывающая сторона функции f() может все еще использовать переданный ей объект:
HasPtr p("some values");
f(p); // по завершении f() память, на которую указывает p.ps,
// освобождается
HasPtr q(p); // теперь и p, и q указывают на недопустимую память!
Память, на которую указывает указатель p (и q), больше недопустима. Она была возвращена операционной системе, когда был удален объект hp (или ret)!
Если класс нуждается в деструкторе, он почти наверняка нуждается также в операторе присвоения копии и конструкторе копий.
Классы, нуждающиеся в копировании, нуждаются также в присвоении, и наоборотХотя большинству классов требуется определить все функции-члены управления копированием (или ни один из них), у некоторых классов есть необходимость только в копировании или присвоении объектов, но нет никакой необходимости в деструкторе.
В качестве примера рассмотрим класс, присваивающий каждому своему объекту уникальный последовательный номер. Такому классу нужен конструктор копий для создания нового уникального последовательного номера для создаваемого объекта. Этот конструктор копировал бы все остальные переменные-члены заданного объекта. Класс нуждался бы также в собственном операторе присвоения копии, чтобы избежать присвоения объекту слева последовательного номера. Однако у этого класса не было бы никакой потребности в деструкторе.
Этот пример иллюстрирует второе эмпирическому правило: если класс нуждается в конструкторе копий, то он почти наверняка нуждается в операторе присвоения копии, и наоборот, — если класс нуждается в операторе присвоения, то он почти наверняка нуждается также в конструкторе копий. Однако нужда в конструкторе копий или операторе присвоения копии не означает потребности в деструкторе.
Упражнения раздела 13.1.4Упражнение 13.14. Предположим, что класс numbered имеет стандартный конструктор, создающий уникальный последовательный номер для каждого объекта, который хранится в переменной-члене mysn. Класс numbered использует синтезируемые функции-члены управления копированием и имеет следующую функцию:
void f(numbered s) { cout << s.mysn << endl; }
Какой вывод создаст следующий код?
numbered a, b = a, с = b;
f(a); f(b); f(c);
Упражнение 13.15. Предположим, что у класса numbered есть конструктор копий, создающий новый последовательный номер. Изменит ли это вывод вызовов в предыдущем упражнении? Если да, то почему? Какой вывод получится?
Упражнение 13.16. Что если параметром функции f() будет const numbered&? Это изменяет вывод? Если да, то почему? Какой вывод получится?
Упражнение 13.17. Напишите версии класса numbered и функции f(), соответствующие трем предыдущим упражнениям, и проверьте правильность предсказания вывода.
13.1.5. Использование спецификатора = default
Используя спецификатор = default, можно явно указать компилятору на необходимость создать синтезируемые версии функций-членов управления копированием (см. раздел 7.1.4):
class Sales_data {
public:
// управление копированием; версии по умолчанию
Sales_data() = default;
Sales_data(const Sales_data&) = default;
Sales_data& operator=(const Sales_data &);
~Sales_data() = default;
// другие члены как прежде
};
Sales_data& Sales_data::operator=(const Sales_data&) = default;
Когда в объявлении функции-члена в теле класса использован спецификатор = default, синтезируемая функция неявно становится встраиваемой (как и любая другая функция-член, определенная в теле класса). Если синтезируемая функция-член класса не должна быть встраиваемой функцией, можно добавить часть = default в ее определение, как это было сделано в определении оператора присвоения копии.
Спецификатор = default можно использовать только для тех функций-членов, у которых есть синтезируемая версия (т.е. стандартный конструктор или функция-член управления копированием).
13.1.6. Предотвращение копирования
Большинство классов должно определить (явно или неявно) стандартный конструктор, конструктор копий и оператор присвоения копии.
Хотя большинство классов должно определять (и, как правило, определяет) конструктор копий и оператор присвоения копии, у некоторых классов нет реальной необходимости в этих функциях. В таких случаях класс должен быть определен так, чтобы предотвращать копирование и присвоение. Например, классы iostream предотвращают копирование, чтобы не позволять нескольким объектам писать или читать из того же буфера ввода-вывода. Казалось бы, предотвратить копирование можно, и не определяя функции-члены управления копированием. Но эта стратегия не сработает: если класс не определит эти функции, то компилятор синтезирует их сам.
Определение функции как удаленнойПо новому стандарту можно предотвратить копирование, определив конструктор копий и оператор присвоения копии как удаленные функции (deleted function). Удаленной называется функция, которая была объявлена, но не может использована никаким другим способом. Чтобы определить функцию как удаленную, за списком ее параметров следует расположить часть = delete:
struct NoCopy {
NoCopy() = default; // использовать синтезируемый стандартный
// конструктор
NoCopy(const NoCopy&) = delete; // без копирования
NoCopy &operator=(const NoCopy&) = delete; // без присвоения
~NoCopy() = default; // используйте синтезируемый деструктор

