Namespaces
Variants

RAII

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

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

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

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

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

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

(since 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 (since C++20) , и многие другие получают свои ресурсы в конструкторах (которые генерируют исключения при ошибках), освобождают их в деструкторах (которые никогда не генерируют исключения) и не требуют явной очистки.

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

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

Примечания

RAII не применим к управлению ресурсами, которые не приобретаются до использования: время ЦПУ, доступность ядер, емкость кэша, емкость пула энтропии, пропускная способность сети, потребление электроэнергии, память стека. Для таких ресурсов конструктор класса C++ не может гарантировать доступность ресурса на протяжении времени жизни объекта, и должны использоваться другие средства управления ресурсами.

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

  1. RAII в ЧаВо по C++ Страуструпа
  2. C++ Core Guidelines E.6 "Используйте RAII для предотвращения утечек"