RAII
- title
- RAII
- type
- concept
- summary
- Resource Acquisition Is Initialization - привязка жизни ресурса к жизни объекта для детерминированного освобождения при выходе из области видимости
- tags
- cpp, memory-management, language-design
- created
- 2026-05-08
- updated
- 2026-07-29
- lang
- ru
- translation_of
- raii
- source_updated
- 2026-07-29
- translated
- 2026-09-01
- translator
- lllm/antigravity/gemini-3.7-flash-medium
RAII - Resource Acquisition Is Initialization ("захват ресурса есть инициализация") - дисциплина привязки времени жизни ресурса к времени жизни объекта. Конструктор захватывает ресурс (память, файловый дескриптор, блокировку, сокет); деструктор его освобождает. Пока объект уничтожается детерминированно, ресурс освобождается столь же детерминированно. Никаких try/finally. Никакой дисциплины парных вызовов в каждом месте использования.
Название вводит в заблуждение настолько, что даже Stroustrup позже назвал его неудачным: важно то, что работает деструктор, а не то, что конструктор выполняет захват. Название "управление ресурсами в пределах области видимости" (scoped resource management) описывает суть честнее. Но аббревиатура прижилась.
Устройство
Тип оборачивает ресурс. Конструктор захватывает; деструктор освобождает; семантика копирования и перемещения делает владение явным на уровне типов. Тот, кто держит объект, владеет ресурсом; когда объект умирает, ресурс освобождается. Деструкторы в C++ срабатывают при выходе из области видимости, при раскрутке стека из-за исключений, при удалении элемента из контейнера и при сбросе умного указателя - единообразно, без участия программиста.
unique_ptr, shared_ptr, lock_guard, fstream, vector и string из стандартной библиотеки - всё это RAII-типы. Как и любой тип в Rust с реализацией Drop: Rust взял RAII за основу и сделал его единственным способом управления памятью.
Почему это работает
Аргумент в stroustrup-memory-leaks чисто практический, а не эстетический: человек способен отслеживать несколько десятков объектов, а не десятки тысяч аллокаций. RAII сводит учёт к минимуму. Как только у ресурса появляется владелец, вопрос кто его освобождает превращается в вопрос кто им владеет, а владение видно прямо в сигнатуре типа. Код с адресной арифметикой не даёт ответа ни на один из этих вопросов; RAII-код по своей конструкции отвечает на оба.
Это применимо не только к памяти. Файловые дескрипторы, мьютексы, транзакции баз данных, ресурсы GPU и счётчики ссылок работают по одной и той же схеме захвата и освобождения. RAII кодирует этот паттерн в системе типов.
Требования к языку
Для RAII необходима детерминированная деструкция - деструкторы, которые вызываются в строго определённых точках (выход из области видимости, удаление из контейнера, сброс умного указателя), а не "когда-нибудь потом, когда заметит GC". Языки с недетерминированными финализаторами (Java, Python, Go) не могут использовать RAII напрямую; они вынуждены полагаться на try-with-resources, блоки with или defer, где программисту каждый раз нужно не забыть явно их вызвать.
Языки со сборкой мусора могут управлять памятью без RAII, потому что память взаимозаменяема - небольшая задержка перед её освобождением ничему не вредит. Но они не могут так же управлять невзаимозаменяемыми ресурсами (дескрипторами файлов, блокировками, сетевыми сокетами), из-за чего в Java появился try-with-resources, а в Python - контекстные менеджеры. RAII - это единообразный ответ C++ и Rust на ту же самую проблему.
Связи
- stroustrup-memory-leaks - каноническая короткая формулировка RAII как средства защиты от утечек памяти
- delightful-integration-tests-rust - RAII в применении к Docker-контейнеру: как только у ресурса появляется владелец, инфраструктура для конкретного теста полностью заменяет setup и teardown, а недостающая поддержка фикстур оказывается ненужной
- simplified-model-of-fil-c - Fil-C добавляет безопасность памяти в C/C++ через GC, потому что в легаси-коде дисциплину RAII обеспечить невозможно
- pointer-provenance - указатели несут идентичность аллокации; RAII помещает эту идентичность внутрь владеющего типа
- no-silver-bullet - RAII стал редким примером удара по привнесённой сложности (accidental complexity), сократившим целый класс ошибок на порядок