close
Пространства имён
Варианты
Действия

Получение ресурса есть инициализация

Материал из cppreference.com
 
 
Язык С++
Общие темы
Управление потоком
Операторы условного выполнения
if
Операторы итерации (циклы)
Операторы перехода
Функции
Объявление функции
Выражение лямбда-функции
Спецификатор inline
Спецификации динамических исключений (до C++17*)
Спецификатор noexcept (C++11)
Исключения
Пространства имён
Типы
Спецификаторы
decltype (C++11)
auto (C++11)
alignas (C++11)
Спецификаторы длительности хранения
Инициализация
Выражения
Альтернативные представления
Литералы
Логические - Целочисленные - С плавающей запятой
Символьные - Строковые - nullptr (C++11)
Определяемые пользователем (C++11)
Утилиты
Атрибуты (C++11)
Types
Объявление typedef
Объявление псевдонима типа (C++11)
Casts
Неявные преобразования - Явные преобразования
static_cast - dynamic_cast
const_cast - reinterpret_cast
Выделение памяти
Классы
Свойства функции класса
explicit (C++11)
static
Специальные функции-элементы
Шаблоны
Разное
 

Получение ресурса есть инициализация или RAII, это техника программирования C++[1][2], которая связывает жизненный цикл ресурса, который должен быть получен перед использованием (выделенная память в куче, поток выполнения, открытый сокет, открытый файл, заблокированный мьютекс, дисковое пространство, подключение к базе данных, всё, что существует в ограниченном количестве) с временем жизни объекта.

RAII гарантирует, что ресурс доступен любой функции, которая может иметь доступ к объекту (доступность ресурса это инвариант класса, что устраняет избыточные тесты во время выполнения). Это также гарантирует, что все ресурсы высвобождаются, когда время жизни их управляющего объекта заканчивается, в порядке, обратном получению. Аналогичным образом, если получение ресурсов завершается с ошибкой (конструктор завершает работу с исключением), все ресурсы, полученные каждым полностью сконструированным элементом и базовым подобъектом, освобождаются в порядке, обратном инициализации. При этом используются основные функции языка (время жизни объекта, выход из области видимости, порядок инициализации и раскручивание стека), чтобы исключить утечку ресурсов и гарантировать безопасность исключений. По другому эта техника называется Управление Ресурсами С Привязкой К Области Видимости (SBRM - Scope-Bound Resource Management), по основному варианту использования, когда время жизни объекта RAII заканчивается из-за выхода из области видимости.

RAII можно резюмировать следующим образом:

  • инкапсулировать каждый ресурс в класс, где
  • конструктор получает ресурс и устанавливает все инварианты класса или генерирует исключение, если это невозможно сделать,
  • деструктор освобождает ресурс и никогда не генерирует исключений;
  • всегда использовать ресурс через экземпляр класса RAII, который либо
  • имеет автоматическую длительность хранения или временное время жизни, или
  • имеет время жизни, которое ограничено временем жизни автоматического или временного объекта.

Семантика перемещения позволяет безопасно передавать право собственности на ресурсы между объектами, между областями видимости, а также внутри и вне потоков, сохраняя при этом безопасность ресурсов.

(начиная с C++11)

Классы с open()/close(), lock()/unlock(), или init()/copyFrom()/destroy() методами являются типичным примером не-RAII классов.

std::mutex m;

void bad() 
{
    m.lock();                    // получает мьютекс
    f();                         // если f() генерирует исключение, мьютекс никогда
                                 // не будет освобождён
    if(!everything_ok()) return; // мьютекс не освобждён при раннем выходе из функции
    m.unlock();                  // если bad() достигает этого оператора мьютекс
                                 // будет освобождён
}

void good()
{
    std::lock_guard<std::mutex> lk(m); // класс RAII: получение мьютекса есть инициализация
    f();                               // если f() генерирует исключение, мьютекс
                                       // будет освобождён
    if(!everything_ok()) return;       // мьютекс освобождён в случае раннего выхода
                                       // из функции
}                                      // если good() завершается корректно мьютекс
                                       // будет освобождён

Стандартная библиотека

Классы бибилиотеки C++, которые управляют собстенными ресурсами, следуют RAII: std::string, std::vector, std::jthread (начиная с C++20) и многие другие получают свои ресурсы в конструкторах (которые генерируют исключения при ошибках), освобождают их в деструкторах (никогда не генерирующих исключений) и не требуют явной очистки.

Кроме того, стандартная библиотека предлагает несколько RAII обёрток для управления предоставленными пользователями ресурсами:

  • std::unique_ptr и std::shared_ptr для управления динамически распределяемой памятью или, с предоставленным пользователем средством удаления, любым ресурсом, представленным обычным указателем;
  • std::lock_guard, std::unique_lock, std::shared_lock для управления мьютексами.
(начиная с C++11)

Примечание

RAII не применяется к управлению ресурсами, которые не были получены перед использованием: процессорное время, количество ядер и объём кэш-памяти, ёмкость энтропийного пула, пропускная способность сети, потребление электроэнергии, память стека.

Внешние ссылки