🕵️
Введение в паттерны
  • Введение в паттерны
  • Паттерны
    • Оглавление
    • Порождающие паттерны
      • Фабричный метод
        • Реализации на С++
        • Реализации на Kotlin
        • Возможные реализации для решения конкретных задач на С++
      • Абстрактная фабрика
        • Реализации на С++
        • Реализации на Kotlin
        • Возможные реализации для решения конкретных задач на С++
      • Прототип
        • Реализации на С++
        • Реализации на Kotlin
        • Реализации на Java
        • Возможные реализации для решения конкретных задач на С++
      • Строитель
        • Реализации на С++
        • Реализации на Kotlin
      • Одиночка
        • Реализации на C++
        • Реализации на Kotlin
        • Возможные реализации для решения конкретных задач на С++
      • Пул объектов
        • Реализации на С++
    • Структурные паттерны
      • Адаптер
        • Реализации на С++
        • Реализации на Kotlin
        • Возможные реализации для решения конкретных задач
      • Декоратор
        • Реализации на С++
        • Реализации на Kotlin
      • Компоновщик
        • Реализации на С++
      • Мост
        • Реализации на С++
      • Заместитель
        • Реализации на С++
        • Реализации на Kotlin
      • Фасад
        • Реализации на С++
      • Приспособленец
        • Реализации на С++
    • Поведенческие паттерны
      • Стратегия
        • Реализации на С++
        • Реализации на Kotlin
      • Команда
        • Реализации на С++
        • Реализации на Kotlin
      • Цепочка обязанностей
        • Реализации на С++
        • Реализации на Kotlin
      • Подписчик-издатель
        • Реализации на С++
        • Реализации на Kotlin
      • Посетитель
        • Реализации на С++
        • Возможные реализации для решения конкретных задач
      • Посредник
        • Реализации на С++
        • Реализации на Kotlin
      • Шаблонный метод
        • Реализации на С++
      • Опекун
        • Реализации на С++
      • Итератор
        • Реализации на С++
        • Реализации на Kotlin
      • Свойство
        • Реализации на С++
        • Возможные реализации для решения конкретных задач
  • Введение в идиомы
  • Идиомы
    • Оглавление
    • RAII
    • Type erasure
      • Контейнеры с type erasure
    • CRTP
    • Статический полиморфизм
    • Shrink to fit
    • Proxy
    • Erase remove
    • Decltype (auto)
    • Copy and swap
    • Safe bool
    • Scope guard
    • Addressof
Powered by GitBook
On this page
  • Альтернативные названия
  • Назначение
  • Решаемые задачи
  • Общая реализация на С++
  • RAII в стандартной библиотеке

Was this helpful?

  1. Идиомы

RAII

Resourse Acquisition Is Initialization

Альтернативные названия

  • CADR (Constructor Acquires, Destructor Releases)

  • SBRM (Scope-Bound Resourse Management)

Назначение

Resource Acquisition Is Initialization (RAII) – программная идиома, смысл которой заключается в том, чтобы с помощью тех или иных программных механизмов получение некоторого ресурса неразрывно совмещалось с инициализацией, а освобождение – с уничтожением объекта.

C++ не имеет встроенного процесса автоматической сборки мусора. Вместо этого программа должна вручную освобождать ресурсы, чтобы избежать утечек. Современный C++ позволяет управлять ресурсами объектов, используя принцип получения ресурсов при инициализации (RAII). Это позволяет избежать утечек памяти, утечек, вызванных некорректной работой с ресурсами (файловых, сетевых, потоков, процессов, баз данных, устройств).

Решаемые задачи

  • необходимость освобождения ресурсов: например памяти или дескрипторов ресурсов

Идиома RAII широко используется в стандартной библиотеке C++, чтобы управлять различными ресурсами, такими как память, файлы, потоки

  • гарантированное освобождение ресурсов при выходе из области видимости

  • позволяет избежать потери данных при освобождении ресурсов

Общая реализация на С++

В приведенном примере класс File использует идиому RAII для открытия файла в конструкторе и закрытия файла в деструкторе. Это гарантирует, что если возникнет исключительная ситуация, файл будет закрыт корректно, а данные не будут утеряны.

Согласно идиоме RAII, нам следует «обернуть» файловый дескриптор в объект специального класса. Тогда открытие файла соответствовало бы инициализации объекта в его конструкторе, а закрытие файла — уничтожению объекта в деструкторе. В случае ошибки при открытии файла мы бы сгенерировали исключение, и объект нашего класса не был бы создан.

#include <cstdio>
#include <exception>
#include <string>
class CannotOpenFileException {};
class File 
{
private:
    std::FILE* f; // файловый дескриптор, который мы оборачиваем
public:
    File(const std::string& name) 
    {
        if (f = std::fopen(name.c_str(), "r"); f == nullptr) 
        {
            throw CannotOpenFileException();
        }
    }
    File(const File&) = delete;
    File& operator = (const File&) = delete;
// Конструктор перемещения
    File(File&& other) noexcept // File&& — ссылка на временный объект
    { 
        f = other.f;
        other.f = nullptr; // забираем владение дескриптором у временного объекта other
    }
// Оператор присваивания с семантикой перемещения
    File& operator = (File&& other) noexcept 
    {
        if (f != nullptr && f != other.f) 
        {
            std::fclose(f); // закрываем файл у текущего объекта
        }
        f = other.f; // забираем владение у временного объекта other
        other.f = nullptr;
        return *this;
    }
    ~File() noexcept 
    {
        if (f != nullptr) 
        {
            std::fclose(f);
        }
    }
    std::string Read() const 
    {
        ...
    }
};
int main() 
{
    try 
    {
        File file("input.txt");
        auto str = file.Read();
        // ...
    } 
    catch (const CannotOpenFileException&) 
    {
        std::cout << "File open failure!\n";
    }
}

RAII в стандартной библиотеке

Некоторые примеры применения:

  • std::unique_ptr и std::shared_ptr - умные указатели, которые используют идиому RAII для автоматического освобождения памяти в деструкторе объекта.

  • std::ifstream и std::ofstream - классы, которые используют идиому RAII для автоматического закрытия файловых потоков в деструкторе объекта.

  • std::lock_guard и std::unique_lock - классы, которые используют идиому RAII для автоматического освобождения блокировок при выходе из области видимости объекта.

  • std::thread - класс, который использует идиому RAII для автоматического завершения потока при выходе из области видимости объекта.

Использование RAII в стандартной библиотеке C++ позволяет создавать более безопасный и понятный код, а также уменьшить количество ошибок и утечек памяти.

PreviousОглавлениеNextType erasure

Last updated 1 year ago

Was this helpful?