Читать книги » Книги » Компьютеры и Интернет » Программирование » C++17 STL Стандартная библиотека шаблонов - Яцек Галовиц

C++17 STL Стандартная библиотека шаблонов - Яцек Галовиц

Читать книгу C++17 STL Стандартная библиотека шаблонов - Яцек Галовиц, Яцек Галовиц . Жанр: Программирование.
C++17 STL Стандартная библиотека шаблонов - Яцек Галовиц
Название: C++17 STL Стандартная библиотека шаблонов
Дата добавления: 15 июль 2023
Количество просмотров: 1 473
(18+) Внимание! Книга может содержать контент только для совершеннолетних. Для несовершеннолетних просмотр данного контента СТРОГО ЗАПРЕЩЕН! Если в книге присутствует наличие пропаганды ЛГБТ и другого, запрещенного контента - просьба написать на почту для удаления материала.
Читать онлайн

C++17 STL Стандартная библиотека шаблонов читать книгу онлайн

C++17 STL Стандартная библиотека шаблонов - читать онлайн , автор Яцек Галовиц

С++ — объектно-ориентированный язык программирования, без которого сегодня немыслима промышленная разработка ПО. В этой замечательной книге описана работа с контейнерами, алгоритмами, вспомогательными классами, лямбда-выражениями и другими интересными инструментами, которыми богат современный С++. Освоив материал, вы сможете коренным образом пересмотреть привычный подход к программированию.
Преимущество издания — в подробном описании стандартной библиотеки шаблонов С++, STL. Ее свежая версия была выпущена в 2017 году. В книге вы найдете более 90 максимально реалистичных примеров, которые демонстрируют всю мощь STL. Многие из них станут базовыми кирпичиками для решения более универсальных задач.
Вооружившись этой книгой, вы сможете эффективно использовать С++17 для создания высококачественного и высокопроизводительного ПО, применимого в различных отраслях.

1 ... 86 87 88 89 90 ... 121 ВПЕРЕД
Перейти на страницу:
switch case мы получаем доступ к variant с помощью вызова get<T> для получения экземпляра типа cat или dog, хранящегося внутри:

  for (const animal &a : l) {

    switch (a.index()) {

    case 0:

      get<dog>(a).woof();

      break;

    case 1:

      get<cat>(a).meow();

      break;

    }

  }

  cout << "-----n";

9. Вместо того чтобы использовать численный индекс типа, можно также явно запросить каждый тип. Вызов get_if<dog> возвращает указатель на объект типа do на внутренний экземпляр типа dog. Если такого экземпляра внутри нет, то указатель равен null. Таким образом, мы можем попробовать получать разные типы до тех пор, пока не преуспеем.

  for (const animal &a : l) {

    if (const auto d (get_if<dog>(&a)); d) {

        d->woof();

    } else if (const auto c (get_if<cat>(&a)); c) {

      c->meow();

    }

  }

  cout << "-----n";

10. Последний — и самый элегантный вариант — это variant::visit. Данная функция принимает объект функции и экземпляр типа variant. Объект функции должен реализовывать разные перегруженные версии для всех вероятных типов, которые может хранить variant. Ранее мы реализовали структуру, имеющую необходимые перегруженные версии оператора (), поэтому можем использовать ее здесь:

  for (const animal &a : l) {

       visit(animal_voice{}, a);

  }

  cout << "-----n";

11. Наконец подсчитаем количество экземпляров типов cat и dog в списке. Предикат is_type<T> может быть специализирован для типов cat и dog, а затем использован в комбинации с std::count_if, чтобы получить количество экземпляров этого типа:

  cout << "There are "

       << count_if(begin(l), end(l), is_type<cat>)

       << " cats and "

       << count_if(begin(l), end(l), is_type<dog>)

       << " dogs in the list.n";

}

12. После компиляции и запуска программы на экране будет список, выведенный три раза. Затем мы увидим, что предикаты is_type, объединенные с count_if, тоже работают хорошо:

$ ./variant Tuba says Meow!

Balou says Woof!

Bobby says Meow!

-----

Tuba says Meow!

Balou says Woof!

Bobby says Meow!

-----

Tuba says Meow!

Balou says Woof!

Bobby says Meow!

-----

There are 2 cats and 1 dogs in the list.

Как это работает

Тип std::variant похож на тип std::any, поскольку они оба могут содержать объекты разных типов, и нужно определять во время работы программы, что именно в них хранится, прежде чем получить доступ к их содержимому.

С другой стороны, тип std::variant отличается от std::any тем, что мы должны объявлять, экземпляры каких типов он может хранить в виде списка шаблонных типов. Экземпляр типа std::variant<A, B, C> должен хранить один экземпляр типа A, B или C. Нельзя сделать так, чтобы в экземпляре типа variant не хранился ни один экземпляр. Это значит, что тип std::variant не поддерживает возможность опциональности.

Экземпляр типа variant<A, B, C> имитирует объединение, которое может выглядеть так:

union U {

  A a;

  B b;

  C c;

};

Проблема с объединениями заключается в том, что нужно создавать собственные механизмы для определения того, экземпляром какого типа оно было инициализировано: A, B или C. Тип std::variant может сделать это за нас, не прилагая особых усилий.

В коде, показанном в этом разделе, мы использовали три разных способа работы с содержимым переменной variant.

Первый способ — применение функции index() типа variant. Для типа variant<A, B, C> она может вернуть индекс 0, если экземпляр был инициализирован переменной типа A, 1 для типа B или 2 для типа C, и т.д. для более сложных вариантов.

Следующий способ — использование функции get_if<T>. Она принимает адрес объекта типа variant и возвращает указатель типа T на его содержимое. Если тип T указан неправильно, то указатель станет нулевым. Кроме того, можно вызвать метод get<T>(x) для переменной типа variant, чтобы получить ссылку на ее содержимое, но если это не сработает, то данная функция сгенерирует исключение (перед выполнением таких преобразований можно проверить правильность типа с помощью булева предиката holds_alternative<T>(x)).

Последний способ получить доступ к значению, хранящемуся в типе variant, — применить функцию std::visit. Она принимает объект функции и экземпляр типа variant. Функция проверяет, какой тип имеет содержимое экземпляра типа variant, а затем вызывает соответствующий перегруженный оператор () объекта функции.

Именно для этих целей мы и реализовали тип animal_voice, поскольку он может быть использован в комбинации с visit и variant<dog, cat>:

struct animal_voice

{

  void operator()(const dog &d) const { d.woof(); }

  void operator()(const cat &c) const { c.meow(); }

};

Последний описанный способ получения доступа к экземплярам, хранящимся в экземплярах типа variant, считается самым элегантным, поскольку в разделах кода, в которых мы получаем доступ к экземпляру, не нужно жестко кодировать возможные типы. Это позволяет проще расширять код.

 

 Утверждение о том, что тип variant не может не иметь значения, было не совсем верным. Добавив тип std::monostate в список вероятных типов, можно указать, что экземпляр не будет хранить значения.

Автоматическое управление ресурсами с помощью std::unique_ptr

Начиная с C++11 в STL появились умные указатели, помогающие отслеживать динамическую память и ее использование. Даже до C++11 существовал класс auto_ptr, который мог управлять динамической памятью, но его было легко применить неправильно.

Однако с появлением умных указателей теперь редко приходится самостоятельно использовать ключевые слова new и delete, и это очень хорошо. Умные указатели — отличный пример автоматического управления памятью. Поддерживая объекты, память для которых выделяется динамически с помощью unique_ptr, мы защищены от утечек памяти, поскольку при разрушении объекта данный класс автоматически вызывает поддерживаемый им объект.

Уникальный указатель выражает принадлежность объекта,

1 ... 86 87 88 89 90 ... 121 ВПЕРЕД
Перейти на страницу:
Комментарии (0)