2011-12-02 20 views
8

संभव डुप्लिकेट:
When is a function try block useful?
Difference between try-catch syntax for functionफ़ंक्शन का उद्देश्य ब्लॉक का प्रयास क्या है?

इस कोड, जबकि कक्षा UseResources अंदर Dog वस्तु का निर्माण एक int अपवाद फेंकता है। एक function try block का उपयोग करता है एक के साथ

Cat() 
Dog() 
~Cat() 
Inside handler 

#include <iostream> 
using namespace std; 

class Cat 
{ 
    public: 
    Cat() { cout << "Cat()" << endl; } 
    ~Cat() { cout << "~Cat()" << endl; } 
}; 

class Dog 
{ 
    public: 
    Dog() { cout << "Dog()" << endl; throw 1; } 
    ~Dog() { cout << "~Dog()" << endl; } 
}; 

class UseResources 
{ 
    class Cat cat; 
    class Dog dog; 

    public: 
    UseResources() : cat(), dog() { cout << "UseResources()" << endl; } 
    ~UseResources() { cout << "~UseResources()" << endl; } 
}; 

int main() 
{ 
    try 
    { 
     UseResources ur; 
    } 
    catch(int) 
    { 
     cout << "Inside handler" << endl; 
    } 
} 

अब, अगर हम UseResources() निर्माता की परिभाषा को बदलने, के रूप में नीचे: int अपवाद एक सामान्य try-catch ब्लॉक और कोड आउटपुट द्वारा पकड़ा जाता है ,

UseResources() try : cat(), dog() { cout << "UseResources()" << endl; } catch(int) {} 

उत्पादन एक ही

है
Cat() 
Dog() 
~Cat() 
Inside handler 

यानी, बिल्कुल अंतिम परिणाम के साथ।

function try block का उद्देश्य क्या है?

+4

एक डुप्लिकेट के डुप्लिकेट का डुप्लिकेट ... – Xeo

+0

क्या यह सी ++ 11 है? मैंने इसे –

+0

@VJovic से पहले कभी नहीं देखा था, मुझे यह नहीं पता कि यह भाषा में कब पेश किया गया था। लेकिन यह नया नहीं है। – Belloc

उत्तर

9

कल्पना कीजिए अगर 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 Catnoexcept (या तो स्पष्ट रूप से या स्पष्ट रूप से)।

इसके विपरीत, यह हमेशा काम करता है:

class UseResources 
{ 
    unique_ptr<Cat> cat; 
    Dog dog; 

    public: 
    UseResources() : cat(new Cat), dog() { cout << "UseResources()" << endl; } 
    ~UseResources() { cout << "~UseResources()" << endl; } 
}; 

संक्षेप में, एक गंभीर कोड गंध के रूप में एक समारोह स्तरीय कोशिश खंड पर लग रहे हो।

+0

दिलचस्प। फ़ंक्शन के साथ अब तक देखे गए उदाहरणों में से कोई भी इस क्लीनअप चीज़ को दिखाता है। लेकिन आपके उदाहरण में कार्यक्रम वैसे भी निरस्त हो जाएगा, तो इस सुविधा के साथ बड़ा सौदा क्या है? यदि ओएस उस पर जा रहा है तो क्लीनअप का उद्देश्य क्या है? – Belloc

+0

अपवाद हैंडलिंग असफलता के माध्यम से काम करने के बारे में नहीं है, यह असफलता को अधिक सुन्दर तरीके से संभालने के बारे में है। यह सुविधा आपको संसाधनों को शानदार ढंग से रिलीज़ करने में मदद करती है। एक व्यावहारिक उदाहरण क्लाइंट क्रैश हो सकता है और इसका उपयोग सर्वर संसाधनों को मुक्त करने के लिए कर सकता है ताकि यह अन्य क्लाइंट के लिए इसे अक्षम नहीं कर सके। – AJG85

+0

@ AJG85 लेकिन 'टर्मिनेट()' हमेशा एक फंक्शन को ब्लॉक करने के लिए बुलाया जाएगा, और इस मामले में किसी भी संसाधन को ओएस द्वारा मुक्त किया जा रहा है। क्या यह सच नहीं है? – Belloc

2

सामान्य कार्य ब्लॉक को अपेक्षाकृत कम उद्देश्य का प्रयास करें। वे शरीर के अंदर एक कोशिश ब्लॉक करने के लिए लगभग समान कर रहे हैं:

int f1() try { 
    // body 
} catch (Exc const & e) { 
    return -1; 
} 

int f2() { 
    try { 
    // body 
    } catch (Exc const & e) { 
    return -1; 
    } 
} 

फर्क सिर्फ इतना है कि थोड़ा बड़ा समारोह-दायरे में समारोह-कोशिश ब्लॉक रहता है, जबकि दूसरा निर्माण समारोह शरीर में रहता है -स्कोप - पूर्व स्कोप केवल फ़ंक्शन तर्कों को देखता है, बाद वाले स्थानीय चर भी (लेकिन यह कोशिश ब्लॉक के दो संस्करणों को प्रभावित नहीं करता है)।

केवल दिलचस्प आवेदन एक निर्माता कोशिश करो-ब्लॉक में आता है:

Foo() try : a(1,2), b(), c(true) { /* ... */ } catch(...) { } 

यही एक रास्ता है कि initializers में से एक से अपवाद पकड़ा जा सकता है। आप अपवाद को संभाल नहीं सकते हैं, क्योंकि संपूर्ण ऑब्जेक्ट निर्माण अभी भी विफल होना चाहिए (इसलिए आपको अपवाद के साथ कैच ब्लॉक से बाहर निकलना होगा, चाहे आप चाहते हैं या नहीं)। हालांकि, यह विशेष रूप से प्रारंभकर्ता सूची से अपवादों को संभालने का एकमात्र तरीका है।

क्या यह उपयोगी है? शायद ऩही। वहाँ अनिवार्य रूप से एक निर्माता कोशिश ब्लॉक और निम्न, अधिक विशिष्ट "को प्रारंभ करने वाली अशक्त और असाइन" पैटर्न, के बीच कोई अंतर है जो अपने आप भयानक है:

Foo() : p1(NULL), p2(NULL), p3(NULL) { 
    p1 = new Bar; 
    try { 
    p2 = new Zip; 
    try { 
     p3 = new Gulp; 
    } catch (...) { 
     delete p2; 
     throw; 
    } 
    } catch(...) { 
    delete p1; 
    throw; 
    } 
} 

आप देख सकते हैं, तो आप एक unmaintainable है , असंभव गड़बड़। एक कन्स्ट्रक्टर-ट्राई-ब्लॉक भी बदतर होगा क्योंकि आप यह भी नहीं बता सकते कि कितने पॉइंटर्स पहले ही असाइन किए जा चुके हैं। तो वास्तव में यह केवल उपयोगी है यदि आपके पास दो रिसाव आवंटन है।अद्यतन:this question पढ़ने के लिए धन्यवाद मुझे इस तथ्य से सतर्क किया गया था कि वास्तव में आप संसाधनों को संसाधनों को साफ करने के लिए कैच ब्लॉक का उपयोग नहीं कर सकते हैं, क्योंकि सदस्य वस्तुओं का जिक्र करना अनिर्धारित व्यवहार है। तो [अंत अद्यतन]

संक्षेप में: यह बेकार है।

+0

"यह बेकार है।" बेशक आप अपवादों का अनुवाद करना चाहते हैं। –

संबंधित मुद्दे