कल्पना कीजिए अगर UseResources
इस तरह परिभाषित किया गया था:
class UseResources
{
class Cat *cat;
class Dog dog;
public:
UseResources() : cat(new Cat), dog() { cout << "UseResources()" << endl; }
~UseResources() { delete cat; cat = NULL; cout << "~UseResources()" << endl; }
};
तो Dog::Dog()
फेंकता है, तो cat
स्मृति रिसाव हो जाएगा। UseResources
का निर्माता कभी पूरा नहीं हुआ, ऑब्जेक्ट पूरी तरह से कभी नहीं बनाया गया था। और इसलिए इसका विनाशक नहीं है। अधिक पूरी तरह से आपके प्रश्न का उत्तर देने
UseResources() try : cat(new Cat), dog() { cout << "UseResources()" << endl; } catch(...)
{
delete cat;
throw;
}
, कंस्ट्रक्टर्स में एक समारोह स्तरीय आज़माएं/कैच ब्लॉक का उद्देश्य विशेष रूप:
इस रिसाव को रोकने के लिए, आप एक समारोह स्तरीय आज़माएं/कैच ब्लॉक का उपयोग करना चाहिए इस तरह के सफाई करने के लिए। फंक्शन-स्तरीय प्रयास/पकड़ ब्लॉक अपवाद निगल नहीं सकते (नियमित रूप से कर सकते हैं)। यदि वे कुछ पकड़ते हैं, तो वे पकड़ने के ब्लॉक के अंत तक पहुंचने पर इसे फिर से फेंक देंगे, जब तक कि आप इसे throw
के साथ स्पष्ट रूप से पुनर्स्थापित नहीं करते। आप एक प्रकार के अपवाद को दूसरे में बदल सकते हैं, लेकिन आप इसे निगल नहीं सकते हैं और ऐसा नहीं चलते जैसे ऐसा नहीं हुआ।
यह एक अन्य कारण है कि कक्षा के सदस्यों के रूप में नग्न पॉइंटर्स के बजाय मूल्य और स्मार्ट पॉइंटर्स का उपयोग क्यों किया जाना चाहिए। क्योंकि, आपके मामले में, यदि आपके पास पॉइंटर्स की बजाय सदस्य मान हैं, तो आपको ऐसा करने की ज़रूरत नहीं है। यह एक नग्न सूचक (या संसाधन का अन्य रूप आरएआईआई ऑब्जेक्ट में प्रबंधित नहीं है) का उपयोग है जो इस तरह की चीज को मजबूर करता है।
ध्यान दें कि यह फ़ंक्शन प्रयास/पकड़ ब्लॉक का एकमात्र वैध उपयोग है।
फ़ंक्शन का उपयोग न करने के अधिक कारण ब्लॉक का प्रयास करें। उपरोक्त कोड संक्षेप में टूटा हुआ है।इस पर विचार करें:
class Cat
{
public:
Cat() {throw "oops";}
};
तो, क्या UseResources
के निर्माता में क्या होता है? खैर, अभिव्यक्ति new Cat
स्पष्ट रूप से फेंक देगा। लेकिन इसका मतलब है कि cat
प्रारंभ नहीं हुआ। जिसका अर्थ है कि delete cat
अपरिभाषित व्यवहार पैदा करेगा।
तुम बस new Cat
के बजाय एक जटिल लैम्ब्डा का उपयोग करके यह सही करने के लिए कोशिश कर सकते हैं:
UseResources() try
: cat([]() -> Cat* try{ return new Cat;}catch(...) {return nullptr;} }())
, dog()
{ cout << "UseResources()" << endl; }
catch(...)
{
delete cat;
throw;
}
कि सैद्धांतिक रूप से समस्या का समाधान होता है, लेकिन यह UseResources
की एक ग्रहण अपरिवर्तनीय टूट जाता है। अर्थात्, UseResources::cat
हमेशा एक वैध सूचक होगा। यदि यह वास्तव में UseResources
का आविष्कार है, तो यह कोड विफल हो जाएगा क्योंकि यह अपवाद के बावजूद UseResources
के निर्माण की अनुमति देता है।
असल में, इस कोड को सुरक्षित बनाने का कोई तरीका नहीं है जब तक कि new Cat
noexcept
(या तो स्पष्ट रूप से या स्पष्ट रूप से)।
इसके विपरीत, यह हमेशा काम करता है:
class UseResources
{
unique_ptr<Cat> cat;
Dog dog;
public:
UseResources() : cat(new Cat), dog() { cout << "UseResources()" << endl; }
~UseResources() { cout << "~UseResources()" << endl; }
};
संक्षेप में, एक गंभीर कोड गंध के रूप में एक समारोह स्तरीय कोशिश खंड पर लग रहे हो।
एक डुप्लिकेट के डुप्लिकेट का डुप्लिकेट ... – Xeo
क्या यह सी ++ 11 है? मैंने इसे –
@VJovic से पहले कभी नहीं देखा था, मुझे यह नहीं पता कि यह भाषा में कब पेश किया गया था। लेकिन यह नया नहीं है। – Belloc