- Фантастика и фэнтези
- Ироническое фэнтези
- Стимпанк
- Детективная фантастика
- Киберпанк
- Попаданцы
- LitRPG
- Космоопера
- Технофэнтези
- Городская фантастика
- Русское фэнтези
- Юмористическая фантастика
- Космическая фантастика
- Боевое фэнтези
- Эпическая фантастика
- Зарубежная фантастика
- Книги магов
- Мистика
- Разная фантастика
- Разное фэнтези
- Любовное фэнтези
- Романтическая фантастика
- Городское фентези
- Историческая фантастика
- Историческое фэнтези
- Социально-философская фантастика
- Сказочная фантастика
- Иностранное фэнтези
- Романтическое фэнтези
- Ироническая фантастика
- Ужасы и Мистика
- Постапокалипсис
- Героическая фантастика
- Фэнтези
- Научная Фантастика
- Социально-психологическая
- Альтернативная история
- Боевая фантастика
- Разная литература
- Пословицы, поговорки
- Шахматы
- Визуальные искусства
- Фанфик
- Авто и ПДД
- Военное
- Отраслевые издания
- Гиды, путеводители
- Зарубежная образовательная литература
- Военная история
- Цитаты из афоризмов
- Современная литература
- Великолепные истории
- Начинающие авторы
- Современная зарубежная литература
- Боевые искусства
- Изобразительное искусство, фотография
- Кино
- Литература 19 века
- Недвижимость
- Музыка, музыканты
- Готические новеллы
- Истории из жизни
- Культура и искусство
- Спецслужбы
- Зарубежная прикладная литература
- Музыка, танцы
- Подростковая литература
- Прочее
- Военная техника, оружие
- Газеты и журналы
- Периодические издания
- Домоводство, Дом и семья
- Любовные романы
- Экономическая литература
- Научные и научно-популярные книги
- О животных
- Биохимия
- Культурология
- Юриспруденция
- Политика
- Психотерапия
- Языкознание
- Научпоп
- Медицина
- Психология, личное
- Радиотехника
- Филология
- Педагогика
- Образовательная литература
- Деловая литература
- Физика
- Науки: разное
- Химия
- Воспитание детей, педагогика
- Детская психология
- Зарубежная публицистика
- Биология
- Архитектура
- Зарубежная психология
- Науки о космосе
- Социология
- Математика
- География
- Беременность, ожидание детей
- Литературоведение
- Транспорт, военная техника
- Обществознание
- Зоология
- География
- Альтернативная медицина
- Иностранные языки
- Ветеринария
- Рефераты
- Астрология
- Биофизика
- Экология
- История Европы
- Учебники
- Шпаргалки
- Государство и право
- Ботаника
- Религиоведение
- История
- Техническая литература
- Прочая научная литература
- Психология
- Детективы и Триллеры
- Справочная литература
- Проза
- Новелла
- Юмор
- Проза
- Историческая проза
- Русская современная проза
- Советская классическая проза
- Повести
- Очерки
- Эссе
- Рассказы
- Зарубежная современная проза
- Сентиментальная проза
- Зарубежная классика
- Афоризмы
- Эпистолярная проза
- Феерия
- Семейный роман/Семейная сага
- Разное
- Антисоветская литература
- Магический реализм
- Русская классическая проза
- Современная проза
- О войне
- Контркультура
- Классическая проза
- Поэзия, Драматургия
- Детская литература
- Детская фантастика
- Детские остросюжетные
- Детские стихи
- Детские приключения
- Внеклассное чтение
- Учебная литература
- Зарубежные детские книги
- Бизнес
- Загадки
- Книги для подростков
- Школьные учебники
- Детский фольклор
- Книги для дошкольников
- Детские детективы
- Детская познавательная и развивающая литература
- Буквари
- Прочая детская литература
- Сказка
- Детская проза
- Детская образовательная литература
- Юмор
- Документальные книги
- Бизнес
- Внешнеэкономическая деятельность
- Тайм-менеджмент
- Кадровый менеджмент
- О бизнесе популярно
- Управление, подбор персонала
- Бизнес
- Менеджмент и кадры
- Продажи
- Экономика
- Ценные бумаги и инвестиции
- Малый бизнес
- Делопроизводство, офис
- Корпоративная культура, бизнес
- Банковское дело
- Финансы
- Зарубежная деловая литература
- Ораторское искусство / риторика
- Личные финансы
- Интернет-бизнес
- Поиск работы
- Государственное и муниципальное управление
- Бухучет и аудит
- Работа с клиентами
- Менеджмент
- Краткое содержание
- Личная эффективность
- Переговоры
- Приключения
- Старинная литература
- Религия и духовность
- Компьютеры и Интернет
- Блог
Читаем без скачивания C++17 STL Стандартная библиотека шаблонов - Яцек Галовиц
Шрифт:
Интервал:
Закладка:
В этом разделе мы рассмотрим unique_ptr и способы его использования.
Как это делается
В этом примере мы напишем программу, которая покажет, как unique_ptr работает с памятью путем создания пользовательского типа, добавляющего некие отладочные сообщения при создании и разрушении объекта. Затем поработаем с уникальными указателями, управляя экземплярами этого типа, для которых память выделяется динамически.
1. Сначала включим необходимые заголовочные файлы и объявим об использовании пространства имен std:
#include <iostream>
#include <memory>
using namespace std;
2. Мы реализуем небольшой класс для объекта, которым будем управлять с помощью unique_ptr. Его конструктор и деструктор станут выводить сообщения на консоль; это поможет узнать о том, что объект был на самом деле удален.
class Foo
{
public:
string name;
Foo(string n)
: name{move(n)}
{ cout << "CTOR " << name << 'n'; }
~Foo() { cout << "DTOR " << name << 'n'; }
};
3. Попробуем реализовать функцию, принимающую в качестве аргументов уникальные указатели, чтобы увидеть, какие ограничения она имеет. Она обрабатывает элемент типа Foo, выводя его название. Обратите внимание: хотя уникальные указатели являются умными, работают без лишних издержек и удобны в использовании, они все еще могут иметь значение null. Это значит, что их все еще нужно проверять перед разыменованием.
void process_item(unique_ptr<Foo> p)
{
if (!p) { return; }
cout << "Processing " << p->name << 'n';
}
4. В функции main откроем еще одну область видимости, создадим два объекта типа Foo в куче и будем управлять ими обоими с помощью уникальных указателей. Создадим первый объект в куче явно, используя оператор new, а затем поместим его в конструктор переменной типа unique_ptr<Foo>, p1. Создадим уникальный указатель p2 путем вызова make_unique<Foo> с аргументами, которые в противном случае передали бы конструктору класса Foo. Этот способ более элегантен, поскольку можно воспользоваться автоматическим определением типов и при первом обращении к объекту он уже будет управляться unique_ptr:
int main()
{
{
unique_ptr<Foo> p1 {new Foo{"foo"}};
auto p2 (make_unique<Foo>("bar"));
}
5. После того как мы покинем область видимости, оба объекта будут разрушены и их память вернется в кучу. Взглянем на функцию process_item и узнаем, как теперь ею пользоваться вкупе с unique_ptr. Если мы создадим новый экземпляр типа Foo, управляемый unique_ptr в вызове функции, то его время жизни будет ограничено областью видимости функции. Когда функция process_item отработает, объект будет уничтожен:
process_item(make_unique<Foo>("foo1"));
6. Если мы хотим вызвать process_item для объекта, который существовал еще до вызова, нужно передать право владения, поскольку данная функция принимает unique_ptr по значению; это значит, что его вызов создаст копию. Но unique_ptr нельзя скопировать, его можно только переместить. Создадим еще два объекта типа Foo и переместим один из них в process_item. Взглянув на консоль, мы увидим, что foo2 был уничтожен после того, как отработала функция process_item, поскольку мы передали ей право владения. Объект foo3 продолжит существовать до тех пор, пока не отработает функция main.
auto p1 (make_unique<Foo>("foo2"));
auto p2 (make_unique<Foo>("foo3"));
process_item(move(p1));
cout << "End of main()n";
}
7. Скомпилируем и запустим программу. Сначала мы увидим вызовы конструктора и деструктора для foo и bar. Они разрушаются после того, как программа покидает дополнительную область видимости. Обратите внимание: объекты разрушаются в порядке, обратном тому, в котором были созданы. Следующая строка конструктора принадлежит foo1 — мы создали этот объект во время вызова process_item. Он уничтожается сразу после вызова функции. Затем создали объекты foo2 и foo3. Первый из них уничтожается сразу после вызова process_item, где мы передали право владения. Другой элемент, foo3, разрушается после выполнения последней строки кода функции main.
$ ./unique_ptr
CTOR foo
CTOR bar
DTOR bar
DTOR foo
CTOR foo1
Processing foo1
DTOR foo1
CTOR foo2
CTOR foo3
Processing foo2
DTOR foo2
End of main()
DTOR foo3
Как это работает
Управлять объектами кучи с помощью std::unique_ptr очень легко. После того как мы инициализировали уникальный указатель так, чтобы он хранил указатель на некий объект, он не может быть случайно удален в какой-то ветке кода.
Если мы присвоим какой-то новый указатель уникальному указателю, то он сначала удалит старый объект, а только затем сохранит новый указатель. Для переменной уникального указателя x можно также вызвать x.reset() только затем, чтобы удалить объект, на который он указывает, не присваивая новый указатель. Еще одна эквивалентная альтернатива повторному присваиванию с помощью x = new_pointer — это x.reset(new_pointer).
Существует единственный способ освободить объект от управления unique_ptr без удаления самого объекта. Это делает функция release, но использовать ее в большинстве ситуаций не рекомендуется.
Поскольку указатели нужно проверять перед разыменованием, они переопределяют некоторые операторы так, чтобы те походили на необработанные указатели. Условия наподобие if (p) {...} и if (p != nullptr) {...} работают так же, как если бы мы проверяли необработанный указатель.
Разыменовать уникальный указатель можно с помощью функции get(), возвращающей необработанный указатель на объект, или непосредственно с применением operator*, что опять же делает их похожими на необработанные указатели.
Одна