Spec-Zone.ru › C++

RAII

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

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

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

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

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

(с C++11)

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

std::mutex m;
 
void bad() 
{
    m.lock();             // acquire the mutex
    f();                  // if f() throws an exception, the mutex is never released
    if (!everything_ok())
        return;           // early return, the mutex is never released
    m.unlock();           // if bad() reaches this statement, the mutex is released
}
 
void good()
{
    std::lock_guard<std::mutex> lk(m); // RAII class: mutex acquisition is initialization
    f();                               // if f() throws an exception, the mutex is released
    if (!everything_ok())
        return;                        // early return, the mutex is released
}                                      // if good() returns normally, the mutex is released

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

Классы библиотек 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 не применяется к управлению ресурсами, которые не приобретаются перед использованием: время процессора, ядра и кэш-память, ёмкость пула энтропии, пропускная способность сети, потребление электроэнергии, память стека.

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

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

© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/cpp/language/raii

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API