Resource Acquisition Is Initialization
Ця стаття містить правописні, лексичні, граматичні, стилістичні або інші мовні помилки, які треба виправити. |
Resource Acquisition Is Initialization (RAII), перекладається як «Отримання ресурсу є ініціалізація» — програмна ідіома, яка використовується в деяких об`єктно-орієнтовних мовах програмування, більшою мірою в C++, звідки вона взяла початок, але також застосовується в D, Ada, і Vala.
Відповідно RAII, утримання ресурсу тісно прив'язане до життєвого циклу об'єкта: алокація ресурсу (отримання) відбувається в момент створення об'єкта за допомогою конструктора, а деаллокація (звільнення) відбувається в момент знищення об'єкта за допомогою деструктора. Якщо об'єкти видаляються правильно, витоків ресурсів не відбувається.
Інші назви цієї ідіоми: Constructor Acquires, Destructor Releases (CADRe)[1] і Scope-based Resource Management (SBRM);[2]
Перевагами RAII, як техніки керування ресурсами є те, що вона забезпечує інкапсуляцію, безпечність при виняткових ситуаціях (для відслідковування ресурсів), і локальність (дозволяє написати логіку отримання ресурсу і вивільнення поруч в одному місці).
Інкапсуляція забезпечується тим, що логіка управління ресурсами описана один раз в класі, а не в кожному місці де вона використовується. Безпека при виняткових ситуаціях забезпечується для стекових ресурсів (ресурси звільняються в тій самій області видимості в якій вони були створені) завдяки прив'язці до життєвого циклу стекової змінної (локальної змінної оголошеної в даному блоці): якщо виникає виняткова ситуація (англ. exception), і існує відповідний блок відловлювання помилок, єдиний код, який буде завжди виконаний після виходу із даної області видимості, це деструктори об'єктів об'явлених в цій області видимості. Локальність, забезпечується завдяки написанню конструктора і деструктора у визначенні класу поруч один з одним.
Управління ресурсами, таким чином, повинно бути тісно прив'язаним до тривалості життя відповідних об'єктів, щоб отримати автоматичну алокацію й очищення. Ресурси створюються в процесі ініціалізації, коли немає жодної можливості використати їх раніше, перш ніж вони стануть доступними й звільнити їх гарантовано, навіть у разі виникнення помилок.
RAII часто використовується для контролювання замикання м'ютексу (mutex) у багатопотокових застосуваннях. В такому випадку, при знищенні об'єкт гарантовано відпускає м'ютекс. Без застосування RAII існує потенційна загроза взаємного блокування (deadlock) м'ютексів. При використанні RAII, в код, який бере м'ютекс включає в собі логіку в якій м'ютекс буде звільнено коли виконання програми вийде за область видимості об'єкта.
Інше типове застосування, це робота з файлами: ми можемо мати об'єкт, який зберігає посилання на файл, який буде відкритий для запису в конструкторі, і закритий в деструкторі. В обох випадках, RAII гарантує лише те, що ресурс буде звільнено коректно, але програмісту слід контролювати безпеку при виникненні виняткових ситуацій власноруч. Якщо код, який проводить модифікацію даних, не є безпечним, м'ютекс може бути не взятий, або файл закритий так, що структура даних файлу буде пошкоджена.
Керування динамічно виділеними об'єктами також можна здійснювати за допомогою RAII. Для цього стандартна бібліотека C++ 11 має реалізацію так званого розумного вказівника std::unique_ptr для об'єкта з одним власником, і std::shared_ptr для об'єктів, на які існує декілька посилань. Схожі реалізації також існують в C++ 98 — std::auto_ptr і в бібліотеці Boost — boost::shared_ptr.
Наступний приклад на C++11 демонструє використання RAII для доступу до файлів і синхронізації м'ютексів:
#include <string>
#include <mutex>
#include <iostream>
#include <fstream>
#include <stdexcept>
void write_to_file (const std::string & message) {
// м’ютекс для захисту доступу для файлу
static std::mutex mutex;
// взяття м’ютексу перед операціями з файлом
std::lock_guard<std::mutex> lock(mutex);
// перевірка відкриття файлу
std::ofstream file("example.txt");
if (!file.is_open())
throw std::runtime_error("Не можливо відкрити файл");
// запис повідомлення до файлу
file << message << std::endl;
// файл буде закритий першим при покиданні області видимості (незалежно від виняткових ситуацій)
// м’ютекс буде звільнений другим (в деструкторі lock)
}
Цей код є безпечним для виняткових ситуацій, оскільки C++ гарантує, що всі стекові об'єкти будуть знищенні після покидання області видимості. Деструктор для обох об'єктів: lock і file гарантовано буде викликаний при поверненні управління із функції, не залежно від того сталася виняткова ситуація (exception) чи ні.[3]
Локальні змінні дозволяють легко керувати кількома ресурсами в одній функції: вони знищуються у зворотньому порядку відповідно до того, як створювалися, а об'єкти знищуються лише тоді, коли вони були вдало створені, якщо не відбулося виняткових ситуацій в момент створення об'єкта.[4]
Використання RAII значно спрощує процедуру управління ресурсами, зменшує об'єми коду і дозволяє пересвідчитися в коректності програми, тому більша частина стандартної бібліотеки C++ дотримується цієї ідіоми.[5]
- ↑ Архівована копія. Архів оригіналу за 4 липня 2014. Процитовано 11 липня 2014.
{{cite web}}
: Обслуговування CS1: Сторінки з текстом «archived copy» як значення параметру title (посилання) - ↑ Masterminds of Programming: Conversations with the Creators of Major Programming Languages, с. 4, на «Google Books», O'Reilly Media, Inc., 21 бер. 2009–496 стор.
- ↑ dtors-shouldnt-throw. Архів оригіналу за 17 лютого 2013. Процитовано 12 лютого 2013.
- ↑ What's the order that local objects are destructed?. Архів оригіналу за 9 жовтня 2014. Процитовано 12 лютого 2013.
- ↑ too-many-trycatch-blocks. Архів оригіналу за 11 травня 2014. Процитовано 12 лютого 2013.
Це незавершена стаття про програмування. Ви можете допомогти проєкту, виправивши або дописавши її. |