Введение
Идиома программирования "Приобретение ресурсов - это инициализация" (RAII) — это идиома программирования, используемая в нескольких объектно-ориентированных, статически типизированных языках программирования для описания определенного поведения языка. В RAII владение ресурсом является инвариантом класса и связано со временем жизни объекта. Выделение ресурсов (или приобретение) происходит во время создания объекта (в частности, инициализации) конструктором, а освобождение ресурсов (выпуск) — во время уничтожения объекта (в частности, финализации) деструктором. Иными словами, приобретение ресурса должно быть успешным для успешной инициализации. Таким образом, ресурс гарантированно будет удерживаться между завершением инициализации и началом финализации (удержание ресурса является инвариантом класса) и будет удерживаться только пока объект существует. Следовательно, если нет утечек объектов, то не будет и утечек ресурсов. RAII наиболее тесно связано с C++, где оно возникло, но также используется в Ada, Vala и Rust. Эта техника была разработана для обеспечения безопасного управления ресурсами при исключениях в C++ в период 1984–1989 годов, в основном Бьярне Строуструпом и Эндрю Кенигом, а сам термин был придуман Строуструпом. Другие названия для этой идиомы включают Constructor Acquires, Destructor Releases (CADRe), а один из конкретных стилей использования называется Scope based Resource Management (SBRM). Последний термин относится к особому случаю автоматических переменных. RAII связывает ресурсы со временем жизни объекта, которое может не совпадать с началом и концом области видимости. (В частности, переменные, выделенные в динамической памяти, имеют время жизни, не связанное с какой-либо областью видимости.) Однако использование RAII для автоматических переменных (SBRM) является наиболее распространенным вариантом использования.
Resource acquisition is initialization (RAII) is a programming idiom used in several object oriented, statically typed programming languages to describe a particular language behavior. In RAII, holding a resource is a class invariant, and is tied to object lifetime. Resource allocation (or acquisition) is done during object creation (specifically initialization), by the constructor, while resource deallocation (release) is done during object destruction (specifically finalization), by the destructor. In other words, resource acquisition must succeed for initialization to succeed. Thus the resource is guaranteed to be held between when initialization finishes and finalization starts (holding the resources is a class invariant), and to be held only when the object is alive. Thus if there are no object leaks, there are no resource leaks. RAII is associated most prominently with C++, where it originated, but also Ada, Vala, and Rust. The technique was developed for exception safe resource management in C++ during 1984–89, primarily by Bjarne Stroustrup and Andrew Koenig, and the term itself was coined by Stroustrup. Other names for this idiom include Constructor Acquires, Destructor Releases (CADRe) and one particular style of use is called Scope based Resource Management (SBRM). This latter term is for the special case of automatic variables. RAII ties resources to object lifetime, which may not coincide with entry and exit of a scope. (Notably variables allocated on the free store have lifetimes unrelated to any given scope.) However, using RAII for automatic variables (SBRM) is the most common use case.
Справочное подсчет
Perl, Python (в реализации CPython) и PHP управляют временем жизни объектов с помощью подсчета ссылок, что делает возможным использование RAII. Объекты, на которые больше нет ссылок, немедленно уничтожаются или завершаются и освобождаются, поэтому деструктор или финализатор может освободить ресурс в этот момент. Однако использование деструкторов/финализаторов не всегда является идиоматичным в таких языках, и в Python оно специально не рекомендуется (в пользу контекстных менеджеров и финализаторов из пакета weakref). При этом время жизни объекта не обязательно привязано к какой-либо области видимости, и объекты могут быть уничтожены недетерминированно или вообще не уничтожены. Это может привести к случайной утечке ресурсов, которые должны были быть освобождены по окончании определенной области видимости. Объекты, хранящиеся в статической переменной (в частности, глобальной переменной), могут не быть завершены при завершении программы, поэтому их ресурсы не будут освобождены; CPython, например, не гарантирует завершение таких объектов. Более того, объекты с циклическими ссылками не будут собраны простым счетчиком ссылок и будут существовать неопределенно долго; даже если они будут собраны (с помощью более сложного сборщика мусора), время и порядок уничтожения будут недетерминированными. В CPython есть детектор циклов, который обнаруживает циклы и завершает объекты в цикле, однако до CPython 3.4 циклы не собирались, если какой-либо объект в цикле имел финализатор.