रिसोर्स एक्विजिशन का क्या मतलब है इनिशियलाइजेशन (RAII)?
रिसोर्स एक्विजिशन का क्या मतलब है इनिशियलाइजेशन (RAII)?
जवाबों:
यह अविश्वसनीय रूप से शक्तिशाली अवधारणा के लिए वास्तव में भयानक नाम है, और शायद नंबर 1 चीजों में से एक है जो सी ++ डेवलपर्स को याद करते हैं जब वे अन्य भाषाओं पर स्विच करते हैं। इस अवधारणा का नाम बदलकर स्कोप-बाउंड रिसोर्स मैनेजमेंट के रूप में स्थापित करने की कोशिश की गई है , हालांकि यह अभी तक पकड़ा नहीं गया है।
जब हम कहते हैं कि 'संसाधन' का अर्थ केवल स्मृति नहीं है - यह फ़ाइल हैंडल, नेटवर्क सॉकेट, डेटाबेस हैंडल, जीडीआई ऑब्जेक्ट हो सकता है ... संक्षेप में, ऐसी चीजें जो हमारे पास एक सीमित आपूर्ति है और इसलिए हमें सक्षम होना चाहिए उनके उपयोग को नियंत्रित करें। 'स्कोप-बाउंड' पहलू का अर्थ है कि वस्तु का जीवनकाल एक चर के दायरे से जुड़ा होता है, इसलिए जब चर दायरे से बाहर हो जाता है तो विनाशकर्ता संसाधन को छोड़ देगा। इसकी एक बहुत उपयोगी संपत्ति यह है कि यह अधिक अपवाद-सुरक्षा के लिए बनाता है। उदाहरण के लिए, इसकी तुलना करें:
RawResourceHandle* handle=createNewResource();
handle->performInvalidOperation(); // Oops, throws exception
...
deleteResource(handle); // oh dear, never gets called so the resource leaks
RAII के साथ
class ManagedResourceHandle {
public:
ManagedResourceHandle(RawResourceHandle* rawHandle_) : rawHandle(rawHandle_) {};
~ManagedResourceHandle() {delete rawHandle; }
... // omitted operator*, etc
private:
RawResourceHandle* rawHandle;
};
ManagedResourceHandle handle(createNewResource());
handle->performInvalidOperation();
इस उत्तरार्द्ध मामले में, जब अपवाद को फेंक दिया जाता है और स्टैक निराधार होता है, तो स्थानीय चर नष्ट हो जाते हैं जो सुनिश्चित करता है कि हमारा संसाधन साफ हो गया है और रिसाव नहीं करता है।
Scope-Bound
स्टोरेज स्पेसिफिकेशंस के साथ सबसे अच्छा नाम पसंद है , तो गुंजाइश के साथ एक इकाई की भंडारण अवधि निर्धारित करें। स्कोप-बाउंड करने के लिए इसे कम करना एक उपयोगी सरलीकरण है, हालांकि यह 100% सटीक नहीं है
यह एक प्रोग्रामिंग मुहावरा है जिसका संक्षिप्त अर्थ है कि आप
यह गारंटी देता है कि संसाधन के उपयोग के दौरान जो कुछ भी होता है, वह अंततः मुक्त हो जाएगा (चाहे सामान्य वापसी के कारण, युक्त वस्तु का विनाश, या एक अपवाद फेंक दिया गया हो)।
यह C ++ में व्यापक रूप से उपयोग किया जाने वाला एक अच्छा अभ्यास है, क्योंकि संसाधनों से निपटने के लिए एक सुरक्षित तरीका होने के अलावा, यह आपके कोड को अधिक क्लीनर भी बनाता है क्योंकि आपको मुख्य कार्यक्षमता के साथ त्रुटि हैंडलिंग कोड को मिक्स करने की आवश्यकता नहीं है।
*
अद्यतन: "स्थानीय" का अर्थ स्थानीय चर या किसी वर्ग का गैर-स्थिर सदस्य चर हो सकता है। बाद के मामले में सदस्य चर को उसके मालिक ऑब्जेक्ट के साथ आरंभीकृत और नष्ट कर दिया जाता है।
**
Update2: जैसा कि @sbi ने बताया, संसाधन - हालांकि अक्सर कंस्ट्रक्टर के अंदर आवंटित किया जाता है - बाहर भी आवंटित किया जा सकता है और एक पैरामीटर के रूप में पारित किया जा सकता है।
open()
/ close()
तरीका नहीं है , बस कंस्ट्रक्टर और विध्वंसक है, इसलिए संसाधन का 'धारण' सिर्फ जीवनकाल है, चाहे वह जीवनकाल हो संदर्भ (स्टैक) या स्पष्ट रूप से (गतिशील आवंटन) द्वारा संभाला
"RAII" का अर्थ है "संसाधन अधिग्रहण प्रारंभिक है" और वास्तव में यह एक मिथ्या नाम है, क्योंकि यह संसाधन अधिग्रहण नहीं है (और किसी वस्तु का आरंभ) इसके साथ संबंध है, लेकिन संसाधन को जारी करना ( किसी वस्तु के विनाश के माध्यम से) )।
लेकिन RAII वह नाम है जो हमें मिला और यह चिपक गया।
इसके बहुत ही दिल में, मुहावरे में स्थानीय, स्वचालित वस्तुओं में रिसोर्सेसिंग संसाधन (मेमोरीज़, ओपन फाइल्स, अनलॉक्ड म्यूटेक्स, यू-नेम-इट) होते हैं , और ऑब्जेक्ट के नष्ट होने पर रिसोर्स को रिलीज़ करने वाले ऑब्जेक्ट को नष्ट करने की सुविधा होती है। इसके अंतर्गत आने वाले दायरे का अंत:
{
raii obj(acquire_resource());
// ...
} // obj's dtor will call release_resource()
बेशक, ऑब्जेक्ट हमेशा स्थानीय, स्वचालित ऑब्जेक्ट नहीं होते हैं। वे एक वर्ग के सदस्य भी हो सकते हैं:
class something {
private:
raii obj_; // will live and die with instances of the class
// ...
};
यदि ऐसी वस्तुएं स्मृति का प्रबंधन करती हैं, तो उन्हें अक्सर "स्मार्ट पॉइंटर्स" कहा जाता है।
इसके कई रूप हैं। उदाहरण के लिए, पहले कोड में स्निपेट पर सवाल उठता है कि अगर कोई नकल करना चाहता है तो क्या होगा obj
। सबसे आसान तरीका यह होगा कि बस नकल को खारिज कर दिया जाए। std::unique_ptr<>
, एक स्मार्ट पॉइंटर जो अगले सी ++ मानक द्वारा चित्रित मानक पुस्तकालय का हिस्सा है, ऐसा करता है।
इस तरह के एक अन्य स्मार्ट पॉइंटर, std::shared_ptr
संसाधन का "साझा स्वामित्व" (एक गतिशील रूप से आवंटित वस्तु) है। यही है, इसे स्वतंत्र रूप से कॉपी किया जा सकता है और सभी प्रतियां एक ही ऑब्जेक्ट को संदर्भित करती हैं। स्मार्ट पॉइंटर इस बात पर नज़र रखता है कि कितनी प्रतियाँ एक ही ऑब्जेक्ट को संदर्भित करती हैं और पिछले एक के नष्ट होने पर उसे हटा देगी।
एक तीसरा संस्करण द्वारा चित्रित किया गया हैstd::auto_ptr
जो एक प्रकार के चाल-शब्दार्थ को कार्यान्वित करता है: एक वस्तु केवल एक सूचक के स्वामित्व में होती है, और किसी वस्तु की प्रतिलिपि बनाने का प्रयास करने से वस्तु का स्वामित्व (प्रति सिंटैक्स हैकरी के माध्यम से) कॉपी संचालन के लक्ष्य तक पहुंच जाएगा।
std::auto_ptr
का अप्रचलित संस्करण है std::unique_ptr
। std::auto_ptr
C ++ 98 में जितना संभव हो उतना नकली चालित std::unique_ptr
शब्दार्थ, C ++ 11 के नए चाल शब्दार्थ का उपयोग करता है। नया वर्ग बनाया गया था क्योंकि C ++ 11 का चाल शब्दार्थ अधिक स्पष्ट है ( std::move
अस्थायी को छोड़कर) की आवश्यकता है, जबकि इसे गैर-कास्ट से किसी भी प्रतिलिपि के लिए डिफ़ॉल्ट किया गया था std::auto_ptr
।
किसी वस्तु का जीवनकाल उसके दायरे से निर्धारित होता है। हालांकि, कभी-कभी हमें ज़रूरत होती है, या यह उपयोगी है, एक ऐसी वस्तु बनाने के लिए जो उस दायरे से स्वतंत्र रूप से रहती है जहां इसे बनाया गया था। C ++ में, ऑपरेटर new
का उपयोग ऐसी वस्तु बनाने के लिए किया जाता है। और ऑब्जेक्ट को नष्ट करने के लिए, ऑपरेटर delete
का उपयोग किया जा सकता है। ऑपरेटर द्वारा बनाई गई वस्तुओं new
को गतिशील रूप से आवंटित किया जाता है, अर्थात गतिशील मेमोरी में आवंटित किया जाता है (जिसे हीप या फ्री स्टोर भी कहा जाता है )। इसलिए, new
तब तक बनाई गई एक वस्तु मौजूद रहेगी, जब तक कि वह स्पष्ट रूप से उपयोग करके नष्ट न हो जाए delete
।
कुछ गलतियाँ जो उपयोग करते समय हो सकती हैं new
और delete
हैं:
new
किसी ऑब्जेक्ट को आवंटित करने और ऑब्जेक्ट को भूलने के लिए उपयोग करना delete
।delete
और फिर दूसरे पॉइंटर का उपयोग करना।delete
किसी ऑब्जेक्ट को दो बार करने की कोशिश करना ।आम तौर पर, स्कोप किए गए चर पसंद किए जाते हैं। हालांकि, आरए II के लिए एक विकल्प के रूप में इस्तेमाल किया जा सकता new
है और delete
एक वस्तु को लाइव इसके दायरे की स्वतंत्र रूप से बनाने के लिए। इस तरह की तकनीक में पॉइंटर को उस ऑब्जेक्ट पर ले जाने के लिए होता है जिसे ढेर पर आवंटित किया गया था और इसे एक हैंडल / मैनेजर ऑब्जेक्ट में रखा गया था । उत्तरार्द्ध में एक विध्वंसक है जो ऑब्जेक्ट को नष्ट करने का ध्यान रखेगा। यह गारंटी देगा कि ऑब्जेक्ट किसी भी फ़ंक्शन के लिए उपलब्ध है जो इसे एक्सेस करना चाहता है, और यह कि ऑब्जेक्ट तबाह हो जाता है जब हैंडल ऑब्जेक्ट का जीवनकाल स्पष्ट सफाई की आवश्यकता के बिना समाप्त हो जाता है।
RAII का उपयोग करने वाले C ++ मानक पुस्तकालय के उदाहरण हैं std::string
और std::vector
।
इस कोड के टुकड़े पर विचार करें:
void fn(const std::string& str)
{
std::vector<char> vec;
for (auto c : str)
vec.push_back(c);
// do something
}
जब आप एक वेक्टर बनाते हैं और आप इसे तत्वों को धक्का देते हैं, तो आप ऐसे तत्वों को आवंटित करने और उनसे निपटने के बारे में परवाह नहीं करते हैं। वेक्टर new
ढेर पर अपने तत्वों के लिए जगह आवंटित करने के लिए और delete
उस स्थान को मुक्त करने के लिए उपयोग करता है। आप वेक्टर के एक उपयोगकर्ता के रूप में जिसे आप कार्यान्वयन विवरण के बारे में परवाह नहीं करते हैं और वेक्टर को लीक नहीं होने पर भरोसा करेंगे। इस मामले में, वेक्टर अपने तत्वों का हैंडल ऑब्जेक्ट है।
मानक पुस्तकालय से अन्य उदाहरण है कि उपयोग आरए II हैं std::shared_ptr
, std::unique_ptr
, और std::lock_guard
।
इस तकनीक का दूसरा नाम SBRM है , जो स्कोप-बाउंड रिसोर्स मैनेजमेंट के लिए छोटा है ।
पुस्तक सी + + डिजाइन पैटर्न के साथ प्रोग्रामिंग पता चला RAII के रूप में वर्णन करता है:
कहाँ पे
संसाधनों को कक्षाओं के रूप में लागू किया जाता है, और सभी पॉइंटर्स के चारों ओर क्लास रैपर होते हैं (उन्हें स्मार्ट पॉइंटर्स बनाते हैं)।
संसाधनों को उनके निर्माणकर्ताओं को आमंत्रित करके प्राप्त किया जाता है और उनके विध्वंसकों को आमंत्रित करके (प्राप्त करने के रिवर्स ऑर्डर में) जारी किया जाता है।
RAII वर्ग के तीन भाग हैं:
RAII का अर्थ है "संसाधन प्राप्ति प्रारंभिक है।" RAII का "संसाधन अधिग्रहण" भाग वह है जहाँ आप कुछ ऐसा शुरू करते हैं जिसे बाद में समाप्त किया जाना चाहिए, जैसे:
"इनिशियलाइज़ेशन" भाग का मतलब है कि अधिग्रहण एक वर्ग के कंस्ट्रक्टर के अंदर होता है।
मैनुअल मेमोरी प्रबंधन एक बुरा सपना है जो प्रोग्रामर कंपाइलर के आविष्कार के बाद से बचने के तरीकों का आविष्कार कर रहे हैं। कचरा संग्रहकर्ताओं के साथ प्रोग्रामिंग भाषाएं जीवन को आसान बनाती हैं, लेकिन प्रदर्शन की कीमत पर। इस लेख में - कचरा कलेक्टर को खत्म करना: RAII वे , टॉपटाल इंजीनियर पीटर गुडस्पीड-निकलस ने हमें कचरा लेनेवालों के इतिहास में एक झलक दी और बताया कि कैसे स्वामित्व और उधार की धारणाएं कचरा लेने वालों को उनकी सुरक्षा की गारंटी के बिना खत्म करने में मदद कर सकती हैं।