2010-12-29 8 views
7

थोड़ी देर में, मुझे कुछ कोडिंग पैटर्न दिखाई देता है जो मैंने वर्षों से किया है और यह मुझे परेशान करता है। मेरे पास कोई विशिष्ट समस्या नहीं है, लेकिन मुझे यह भी याद नहीं है कि मैंने उस पैटर्न को क्यों अपनाया है, और इसके कुछ पहलू कुछ विरोधी पैटर्न से मेल खाते हैं। यह हाल ही में मेरे साथ डब्लूआरटी हुआ है कि मेरे कुछ कोड अपवादों का उपयोग कैसे करते हैं।क्या मेरा सी ++ पकड़ खंड, अपवाद वर्गों के परिवार, और विनाश सायन का उपयोग है?

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

class widget_error {}; 
class widget_error_all_wibbly : public widget_error {}; 
class widget_error_all_wobbly : public widget_error {}; 

void wibbly_widget() 
{ 
    throw widget_error_all_wibbly(); 
} 

void wobbly_widget() 
{ 
    throw widget_error_all_wobbly(); 
} 

void call_unknown_widget (void (*p_widget)()) 
{ 
    try 
    { 
    p_widget(); 
    } 
    catch (const widget_error &p_exception) 
    { 
    // Catches either widget_error_all_wibbly or 
    // widget_error_all_wobbly, or a plain widget_error if that 
    // is ever thrown by anything. 
    } 
} 

यह अब मुझे चिंता है, क्योंकि मैंने देखा है कि एक वर्ग उदाहरण एक समारोह के भीतर (फेंक के भाग के रूप में) का निर्माण किया है, लेकिन (p_Exception के माध्यम से संदर्भित है पकड़ने के बाद "पैरामीटर") उस समारोह के बाद बाहर निकला है। यह आम तौर पर एक विरोधी पैटर्न होता है - किसी स्थानीय चर या किसी फ़ंक्शन के भीतर अस्थायी रूप से निर्मित पॉइंटर, लेकिन फ़ंक्शन से बाहर निकलने पर बाहर निकलता है, सामान्य रूप से एक खतरनाक संदर्भ/सूचक होता है क्योंकि स्थानीय चर/अस्थायी नष्ट हो जाता है और स्मृति मुक्त हो जाती है जब समारोह निकलता है।

कुछ त्वरित परीक्षणों से पता चलता है कि उपरोक्त फेंक शायद ठीक है - फ़ंक्शन से निकलने पर फेंक दिया गया उदाहरण नष्ट नहीं होता है, लेकिन जब पकड़ने वाला क्लॉज इसे पूरा करता है तो नष्ट हो जाता है - जब तक कि कैच ब्लॉक रिथ्रो न हो अपवाद, इस मामले में अगला कैच ब्लॉक यह काम करता है।

मेरा शेष घबराहट इसलिए है क्योंकि एक या दो कंपाइलरों में एक परीक्षण चलाने का कोई प्रमाण नहीं है कि मानक क्या कहता है, और जब से मेरा अनुभव कहता है कि जो मुझे लगता है वह सामान्य ज्ञान अक्सर भाषा की गारंटी के लिए अलग होता है।

तो - अपवादों को संभालने का यह पैटर्न (संदर्भ प्रकार का उपयोग करके उन्हें पकड़ना) सुरक्षित है? या मैं जैसे कुछ और कर दिया जाना चाहिए, ...

  • कुछ है कि लग रहा है (जब फेंक दिया) बहुत एक अस्थायी तरह के पकड़ने (और स्पष्ट रूप से हटाने) संदर्भ के बजाय ढेर-आवंटित उदाहरणों की ओर इशारा?
  • एक स्मार्ट सूचक वर्ग का उपयोग कर?
  • "पास-बाय-वैल्यू" कैच क्लॉज का उपयोग करके, और यह स्वीकार करते हुए कि मैं एक कैचुक्रम से किसी भी अपवाद वर्ग को किसी पकड़ खंड के साथ नहीं पकड़ सकता?
  • कुछ मैंने सोचा नहीं है?
+2

इसके अलावा [वर्चुअल विरासत का उपयोग करें] (http://www.boost.org/community/error_handling.html)। – ybungalobill

+1

@ybungalobill - मैंने सोचा कि यह एक मजाक था, फिर मैंने लिंक पढ़ा। दिलचस्प बिंदु। उपयोगी उत्तरों के लिए – Steve314

उत्तर

9

यह ठीक है। निरंतर संदर्भ (और पॉइंटर्स को पकड़ने में बुरा) द्वारा अपवादों को पकड़ना वास्तव में अच्छा है। मूल्य से पकड़ना एक अनावश्यक प्रति बनाता है। कंपाइलर अपवाद (और इसके विनाश) को सही तरीके से संभालने के लिए पर्याप्त स्मार्ट है - बस अपने कैच ब्लॉक के बाहर अपवाद संदर्भ का उपयोग करने की कोशिश न करें ;-)

असल में, मैं अक्सर जो करता हूं वह मेरा उत्तराधिकारी है std :: runtime_error से पदानुक्रम (जो std :: अपवाद से विरासत में मिलता है)। फिर मैं .what() का उपयोग कर सकता हूं, और अधिक अपवादों को संभालने के दौरान भी कम पकड़ ब्लॉक का उपयोग कर सकता हूं।

+0

+1 सभी दौर। मैं फटा हुआ हूं जो सबसे उपयोगी है, लेकिन अंततः इसे स्वीकार करने का फैसला किया। – Steve314

6

यह पैटर्न निश्चित रूप से सुरक्षित है।

ऐसे विशेष नियम हैं जो एक फेंकने वाली वस्तु के जीवनकाल को बढ़ाते हैं। प्रभावी रूप से, यह तब तक अस्तित्व में है जब तक इसे संभाला जा रहा है और यह पिछले catch ब्लॉक के अंत तक मौजूद होने की गारंटी है।

एक बहुत ही सामान्य मुहावरा, उदाहरण के लिए, std::exception से कस्टम अपवाद प्राप्त करने के लिए, अपने what() सदस्य समारोह को ओवरराइड, और संदर्भ से इसे पकड़ ताकि आप एक पकड़ खंड के साथ अपवाद की एक विस्तृत विविधता से त्रुटि संदेश मुद्रित कर सकते हैं।

4

हां। अब तक सब ठीक है।

व्यक्तिगत रूप से मैं सभी अपवाद calsses के आधार के रूप में std :: runtime_error का उपयोग करता हूं। यह त्रुटि संदेश इत्यादि को संभालता है

इसके अलावा आपको और अपवाद भी घोषित नहीं करना चाहिए। केवल उन चीजों के लिए अपवाद परिभाषित करें जिन्हें वास्तव में पकड़ा जा सकता है और तय किया जा सकता है। उन चीज़ों के लिए अधिक सामान्य अपवाद का उपयोग करें जिन्हें पकड़ा या तय नहीं किया जा सकता है।

उदाहरण के लिए: यदि मैं लाइब्रेरी ए विकसित करता हूं तो मेरे पास std :: runtime_error से प्राप्त एएक्सप्शन होगा। यह अपवाद लाइब्रेरी से सभी सामान्य अपवादों के लिए उपयोग किया जाएगा। किसी विशिष्ट अपवाद के लिए जहां लाइब्रेरी का उपयोगकर्ता वास्तव में अपवाद के साथ कुछ (फिक्स या मिटिगेट) पकड़ सकता है और कर सकता है, तो मैं एएक्सप्शन से व्युत्पन्न एक विशिष्ट अपवाद तैयार करूंगा (लेकिन केवल तभी होता है जब अपवाद के साथ कुछ किया जा सके)।

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