Ռեսուրսի ստանալը ինիցալիզացիա է | |
---|---|
Տեսակ | Ստեղծող |
Նշանակություն | Ռեսուրսների ստանալը կապված է ինցիալիզացիայի հետ, իսկ ազատումը` օբյեկտի վերացման հետ։ |
Կիրառություն | Ծրագրային բացառումների մշակման համար |
Առավելություններ | ապահովում է ինկապսուլյացիա, բացառումների անվտանգություն |
Նկարագրությունը ԳօՖի "Design Patterns" գրքում | Չկա |
Ռեսուրսի ստանալն ինիցալիզացիա է (անգլ.՝ Resource Acquisition Is Initialization (RAII)) նախագծման ձևանմուշն իրենից ներկայացնում է օբյեկտ կողմնորոշված ծրագրավորման ստեղծման ձևանմուշ։ Այստեղ ծրագրավորման որոշակի ռեսուրսների ստանալը անխզելիորեն համատեղվում է ինիցիալիզացիայի հետ, իսկ ազատումը՝ օբյեկտի վերացման հետ։
Նման վարքագծի տիպիկ օրինակ է, բայց և ոչ միակը, ռեսուրսների ստացումը կոնստրուկտորների միջոցով իրագործելը, իսկ ազատումը համապատասխան դասի դեստրուկտորների միջոցով իրականացնելը։ Քանի որ դեստրուկտորն ավտոմատ կերպով կանչվում է ծրագրի դուրս գալուց, ապա ռեսուրսը հաստատապես կազատվի փոփոխականի վերացումից հետո։ Այս պնդումը ճիշտ է նույնիսկ այն դեպքում, երբ ծրագիրն ունի բացառություններ։ Դրա պատճառով էլ RAII-ն հանդիսանում է առանցքային հասկացություն ծրագրավորման լեզուներում բացառությունների մշակման համար, որտեղ օբյեկտների կոնստրուկտորներն ու դեստրուկտորները կանչվում են ավտոմատ կերպով (օրինակ C++ լեզվում)։
Այս հասկացությունը կարող է օգտագործվել բոլոր բաշխվող օբյեկտների կամ ռեսուրսների համար.
RAII -ի կարևոր օգտագործում է հանդիսանում «խելացի ցուցիչները»` դասերը, ինկապսուլյացիայի միջոցով դինամիկ հիշողության կառավարումը։ Օրինակ, C++ լեզվի կաղապարների ստանդարտ գրադարանում այս նպատակի համար գոյություն ունի auto_ptr
դասը (C++11-ում այն փոխարինվել է unique_ptr
դասով)։
RAII-ի ռեսուրսների ղեկավարման մեթոդիկայի առավելությունն այն է, որ այն ապահովում է ինկապսուլյացիա, բացառումների անվտանգություն (ստեկի (անգլ.՝ stack) ռեսուրսների համար) և լոկալություն (դա թույլ է տալիս ստացումն (անգլ.՝ acquisition) ու տրամաբանական իրականացումը գրել կողք-կողքի)։
Ինկապսուլյացիան տրամադրվում է, քանի որ ռեսուրսների տրամադրման տրամաբանությունը դասի մեջ բնորոշվում է մեկ անգամ, այլ ոչ թե ամեն կանչի ժամանակ։ Բացառումների անվտանգությունը տրամադրվում է ստեկի ռեսուրսների համար (ռեսուրսներ, որոնք հատկացվում են ճիշտ այն ծավալով, որոնք որ նրանք ձեռք են բերել)` ռեսուրսի կյանքի տևողությունը կապելով ստեկի փոփոխականի հետ։ Եթե առաջ է եկել բացառում և բացառման մշակումը գտնվում է իր տեղում, միայն ծրագիրը, որը պետք է իրականացվի ընթացիք տարածքից դուրս գալու համար, հանդիսանում է տվյալ տարածքում հայտարարված օբյեկտների դեստրուկտոր։ Ի վերջո, դասում կոնստրուկտորն ու դեստրուկտորը հայտարարվում են կողք-կողքի՝ դասի բնորոշման մեջ։
Հետևաբար, ռեսուրսների կառավարումը պետք է կապված լինի օբյեկտների կյանքի տևողության հետ, որպեսզի հնարավոր լինի ավտոմատ կերպով ստանալ նրանց բաշխումը և հարկ եղած դեպքում վերացնել։ Ինիցիալիզացիայի ժամանակ հատկացված ռեսուրսները, նույնիսկ եթե երբևէ հասանելի չեն լինելու, այդ օբյեկտների մեջ հայտարարվում են իրենց դեստրուկտորներով, որը և երաշխավորում է նրանց հեռացումը նույնիսկ ծրագրի կողմից բացառություններ նետելու ժամանակ։
RAII-ն համեմատելով Java-այում օգտագործվող finally
կոդի հետ, Ստրաստուպն ասել է. Իրական համակարգերում գոյություն ունեն ավելի շատ ռեսուրսների հատկացումներ, քան ռեսուրսների տեսակներն են։ Այսպիսով «Ռեսուրսի ստանալը ինիցիալիզացիա է» տեխնիկան բերում է ծրագրավորման կոդի ավելի փոքր չափերի, քան finally
կոնստրուկցիան է[1]։
Հետևյալ օրինակը ցույց է տալիս RAII-ի օգտագործումը մյուտեքսը անգլ.՝ mutex կողպենքելու համար.
#include <string>
#include <mutex>
#include <iostream>
#include <fstream>
#include <stdexcept>
void write_to_file (const std::string & message) {
// mutex to protect file access
static std::mutex mutex;
// lock mutex before accessing file
std::lock_guard<std::mutex> lock(mutex);
// try to open file
std::ofstream file("example.txt");
if (!file.is_open())
throw std::runtime_error("unable to open file");
// write message to file
file << message << std::endl;
// file will be closed 1st when leaving scope (regardless of exception)
// mutex will be unlocked 2nd (from lock destructor) when leaving
// scope (regardless of exception)
}
Այս կոդը հանդիսանում է անվտանգության բացառում, քանի որ C ++ լեզուն երաշխավորում է, որ բոլոր օբյեկտները կվերացվեն ծրագրի ավարտից հետո։ Ֆայլերի և արգելափակիչների (անգլ.՝ lock) դեստրուկտորներն երաշխավորված կերպով կանչվում են ֆունկցիայի կանչից հետո՝ անկախ նրանից թե ծրագրի կոդը բացառություն նետում է, թե ոչ[2]։
Լոկալ փոփոխականները թույլ են տալիս մի ֆունկցիայի շրջանակներում հեշտությամբ կառավարել մի քանի ռեսուրսներ։ Ռեսուրսները վերանում են ըստ ստեղծման հակառակ հերթականության, իսկ օբյեկտը վերացվում է միայն այն դեպքում, երբ այն ամբողջովին կառուցված է։ Այսինքն բացառումը չի տարածվում իր սեփական կոնստրուկտորի վրայից[3]։
RAII-ի օգտագործումը զգալիորեն հեշտացնում է ռեսուրսների կառավարումը, փոքրացնում է ընդհանուր ծրագրային կոդի ծավալը և օգնում է երաշխավորել ծրագրի կոռեկտությունը։ Այդ պատճառով էլ այն խստորեն խորհուրդ է տրվում օգտագործել C++ լեզվում և լեզվի ստանդարտ գրադարաններից մեծամասնությունն հետևում է այդ կանոնին[4]։
|