Следующий способ — использование функции get_if
variant
и возвращает указатель типа T
на его содержимое. Если тип T
указан неправильно, то указатель станет нулевым. Кроме того, можно вызвать метод get(x)
для переменной типа variant
, чтобы получить ссылку на ее содержимое, но если это не сработает, то данная функция сгенерирует исключение (перед выполнением таких преобразований можно проверить правильность типа с помощью булева предиката holds_alternative(x)
).Последний способ получить доступ к значению, хранящемуся в типе variant
std::visit
. Она принимает объект функции и экземпляр типа variant
. Функция проверяет, какой тип имеет содержимое экземпляра типа variant
, а затем вызывает соответствующий перегруженный оператор ()
объекта функции.Именно для этих целей мы и реализовали тип animal_voice, поскольку он может быть использован в комбинации с visit
variant
: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
, мы защищены от утечек памяти, поскольку при разрушении объекта данный класс автоматически вызывает поддерживаемый им объект.Уникальный указатель выражает принадлежность объекта, на который ссылается, и выполняет свою задачу по освобождению его памяти, если та более не используется. Этот класс может навсегда освободить нас от утечек памяти (во всяком случае вместе со своими компаньонами shared_ptr
weak_ptr
, но в этом примере мы концентрируемся только на unique_ptr
). Самая приятная особенность заключается в том, что он nullptr
после разрушения объекта, на который он указывает, и это нужно учитывать при оптимизации. Большая часть кода, управляющего динамической памятью и написанного вручную, делает то же самое.)В этом разделе мы рассмотрим unique_ptr
Как это делается
В этом примере мы напишем программу, которая покажет, как unique_ptr
1. Сначала включим необходимые заголовочные файлы и объявим об использовании пространства имен std
#include
#include
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