Ռեսուրսի ստանալն ինիցիալիզացիա է

Վիքիպեդիայից՝ ազատ հանրագիտարանից
Ռեսուրսի ստանալը ինիցալիզացիա է
ՏեսակՍտեղծող
ՆշանակությունՌեսուրսների ստանալը կապված է ինցիալիզացիայի հետ, իսկ ազատումը` օբյեկտի վերացման հետ։
ԿիրառությունԾրագրային բացառումների մշակման համար
Առավելություններապահովում է ինկապսուլյացիա, բացառումների անվտանգություն
Նկարագրությունը ԳօՖի
"Design Patterns" գրքում
Չկա

Ռեսուրսի ստանալն ինիցալիզացիա է (անգլ.՝ Resource Acquisition Is Initialization (RAII)) նախագծման ձևանմուշն իրենից ներկայացնում է օբյեկտ կողմնորոշված ծրագրավորման ստեղծման ձևանմուշ։ Այստեղ ծրագրավորման որոշակի ռեսուրսների ստանալը անխզելիորեն համատեղվում է ինիցիալիզացիայի հետ, իսկ ազատումը՝ օբյեկտի վերացման հետ։

Նման վարքագծի տիպիկ օրինակ է, բայց և ոչ միակը, ռեսուրսների ստացումը կոնստրուկտորների միջոցով իրագործելը, իսկ ազատումը համապատասխան դասի դեստրուկտորների միջոցով իրականացնելը։ Քանի որ դեստրուկտորն ավտոմատ կերպով կանչվում է ծրագրի դուրս գալուց, ապա ռեսուրսը հաստատապես կազատվի փոփոխականի վերացումից հետո։ Այս պնդումը ճիշտ է նույնիսկ այն դեպքում, երբ ծրագիրն ունի բացառություններ։ Դրա պատճառով էլ RAII-ն հանդիսանում է առանցքային հասկացություն ծրագրավորման լեզուներում բացառությունների մշակման համար, որտեղ օբյեկտների կոնստրուկտորներն ու դեստրուկտորները կանչվում են ավտոմատ կերպով (օրինակ C++ լեզվում)։

Ընդհանուր հասկացողություններ[խմբագրել | խմբագրել կոդը]

  • Client - հայցող
  • Instance - նմուշ
  • Implementation - իրականացում
  • Product - արգասիք
  • Exception - բացառում

Կիրառություն[խմբագրել | խմբագրել կոդը]

Այս հասկացությունը կարող է օգտագործվել բոլոր բաշխվող օբյեկտների կամ ռեսուրսների համար.

  • դինամիկ հիշողություն հատկացնելու համար
  • ֆայլերի կամ սարքավորումների բացման համար
  • մյուտեքսների կամ կրիտիկական սեկցիաների համար

RAII -ի կարևոր օգտագործում է հանդիսանում «խելացի ցուցիչները»` դասերը, ինկապսուլյացիայի միջոցով դինամիկ հիշողության կառավարումը։ Օրինակ, C++ լեզվի կաղապարների ստանդարտ գրադարանում այս նպատակի համար գոյություն ունի auto_ptr դասը (C++11-ում այն փոխարինվել է unique_ptr դասով)։

Առավելություններ[խմբագրել | խմբագրել կոդը]

RAII-ի ռեսուրսների ղեկավարման մեթոդիկայի առավելությունն այն է, որ այն ապահովում է ինկապսուլյացիա, բացառումների անվտանգություն (ստեկի (անգլ.՝ stack) ռեսուրսների համար) և լոկալություն (դա թույլ է տալիս ստացումն (անգլ.՝ acquisition) ու տրամաբանական իրականացումը գրել կողք-կողքի)։

Ինկապսուլյացիան տրամադրվում է, քանի որ ռեսուրսների տրամադրման տրամաբանությունը դասի մեջ բնորոշվում է մեկ անգամ, այլ ոչ թե ամեն կանչի ժամանակ։ Բացառումների անվտանգությունը տրամադրվում է ստեկի ռեսուրսների համար (ռեսուրսներ, որոնք հատկացվում են ճիշտ այն ծավալով, որոնք որ նրանք ձեռք են բերել)` ռեսուրսի կյանքի տևողությունը կապելով ստեկի փոփոխականի հետ։ Եթե առաջ է եկել բացառում և բացառման մշակումը գտնվում է իր տեղում, միայն ծրագիրը, որը պետք է իրականացվի ընթացիք տարածքից դուրս գալու համար, հանդիսանում է տվյալ տարածքում հայտարարված օբյեկտների դեստրուկտոր։ Ի վերջո, դասում կոնստրուկտորն ու դեստրուկտորը հայտարարվում են կողք-կողքի՝ դասի բնորոշման մեջ։

Հետևաբար, ռեսուրսների կառավարումը պետք է կապված լինի օբյեկտների կյանքի տևողության հետ, որպեսզի հնարավոր լինի ավտոմատ կերպով ստանալ նրանց բաշխումը և հարկ եղած դեպքում վերացնել։ Ինիցիալիզացիայի ժամանակ հատկացված ռեսուրսները, նույնիսկ եթե երբևէ հասանելի չեն լինելու, այդ օբյեկտների մեջ հայտարարվում են իրենց դեստրուկտորներով, որը և երաշխավորում է նրանց հեռացումը նույնիսկ ծրագրի կողմից բացառություններ նետելու ժամանակ։

RAII-ն համեմատելով Java-այում օգտագործվող finallyկոդի հետ, Ստրաստուպն ասել է. Իրական համակարգերում գոյություն ունեն ավելի շատ ռեսուրսների հատկացումներ, քան ռեսուրսների տեսակներն են։ Այսպիսով «Ռեսուրսի ստանալը ինիցիալիզացիա է» տեխնիկան բերում է ծրագրավորման կոդի ավելի փոքր չափերի, քան finally կոնստրուկցիան է[1]։

C++11 լեզվով օրինակ[խմբագրել | խմբագրել կոդը]

Հետևյալ օրինակը ցույց է տալիս 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]։

Ծանոթագրություններ[խմբագրել | խմբագրել կոդը]

  1. Bjarne Stroustrup Why doesn't C++ provide a "finally" construct? Accessed on 2013-01-02.
  2. «dtors-shouldnt-throw». Վերցված է 2013 թ․ փետրվարի 12-ին.
  3. «What's the order that local objects are destructed?». Վերցված է 2013 թ․ փետրվարի 12-ին.
  4. «too-many-trycatch-blocks». Վերցված է 2013 թ․ փետրվարի 12-ին.