मुझे "कोशिश" - "पकड़ने" में हर ब्लॉक को क्यों नहीं लपेटना चाहिए?


430

मेरा हमेशा से यह विश्वास रहा है कि यदि कोई विधि अपवाद को फेंक सकती है तो यह बेकार की कोशिश ब्लॉक के साथ इस कॉल की रक्षा नहीं करना है।

मैंने अभी पोस्ट किया है ' आपको हमेशा उन कॉल को रैप करना चाहिए जो कि कोशिश कर सकते हैं, ब्लॉक पकड़ सकते हैं। ' इस सवाल पर और कहा गया था कि यह' उल्लेखनीय रूप से बुरी सलाह 'थी - मैं यह समझना चाहूंगा कि क्यों।


4
अगर मुझे पता था कि एक विधि अपवाद को फेंक देगी, तो मैंने इसे पहले स्थान पर सही किया होगा। यह इसलिए है क्योंकि मुझे पता नहीं है कि कोड कहां और क्यों अपवादों को फेंक देगा जो मैं उन्हें स्रोत पर पकड़ता हूं (प्रत्येक विधि - एक सामान्य कोशिश-कैच)। उदाहरण के लिए एक टीम ने मुझे पहले वाले डेटाबेस के साथ एक कोड आधार दिया। SQL लेयर में ट्राई कैच जोड़ने के बाद ही कई कॉलम छूट गए और पकड़े गए। दूसरी बात, मैं ऑफ़लाइन डीबगिंग के लिए विधि नाम और संदेश को लॉग इन कर सकता हूं- अन्यथा मुझे नहीं पता कि यह कहां से उत्पन्न हुआ है।
चक्र

जवाबों:


340

एक विधि को केवल एक अपवाद को पकड़ना चाहिए जब वह इसे कुछ समझदार तरीके से संभाल सकता है।

अन्यथा, इसे ऊपर से पास करें, इस उम्मीद में कि कॉल स्टैक को उच्चतर करने का एक तरीका समझ में आता है।

जैसा कि अन्य ने नोट किया है, कॉल स्टैक के उच्चतम स्तर पर एक अनहेल्ड अपवाद हैंडलर (लॉगिंग के साथ) यह सुनिश्चित करने के लिए अच्छा है कि कोई भी घातक त्रुटि लॉग की जाए।


12
यह भी ध्यान देने योग्य है कि tryब्लॉक करने के लिए लागत (उत्पन्न कोड के संदर्भ में) हैं। स्कॉट मेयर्स के "मोर इफेक्टिव सी ++" में अच्छी चर्चा है।
निक मेयर

28
वास्तव tryमें किसी भी आधुनिक सी संकलक में ब्लॉक मुक्त हैं, यह जानकारी निक द्वारा दिनांकित है। मैं एक शीर्ष-स्तरीय अपवाद हैंडलर होने के बारे में भी असहमत हूं क्योंकि आप स्थानीयता जानकारी खो देते हैं (वास्तविक स्थान जहां निर्देश विफल हुआ)।
ब्लाइंडी

31
@ स्वतंत्र रूप से: शीर्ष अपवाद हैंडलर अपवाद को संभालने के लिए नहीं है, लेकिन वास्तव में जोर से चिल्लाने के लिए कि एक अखंड अपवाद था, अपना संदेश दें, और कार्यक्रम को एक सुंदर तरीके से समाप्त करें (कॉल के बजाय 1 लौटें terminate) । यह एक सुरक्षा तंत्र के अधिक है। इसके अलावा, try/catchकोई अपवाद नहीं है जब कम या ज्यादा मुक्त हैं। जब कोई एक प्रचार करता है तो उसे फेंके जाने और पकड़े जाने में हर बार समय लगता है, इसलिए try/catchकेवल पुनर्खरीद की एक श्रृंखला महंगी नहीं होती है।
Matthieu M.

17
मैं असहमत हूं कि आपको हमेशा बिना किसी अपवाद के दुर्घटनाग्रस्त होना चाहिए। आधुनिक सॉफ़्टवेयर डिज़ाइन बहुत ही कंपार्टमेंटलाइज़्ड है, इसलिए आपको बाकी एप्लिकेशन (और अधिक महत्वपूर्ण रूप से, उपयोगकर्ता!) को दंडित क्यों करना चाहिए क्योंकि सिर्फ एक त्रुटि थी? बिलकुल आखिरी चीज़ जो आप करना चाहते हैं, को क्रेश करना, बहुत कम से कम उपयोगकर्ता को कोड की कुछ छोटी खिड़की देने की कोशिश करें जो उन्हें काम को बचाने देगा भले ही शेष एप्लिकेशन तक पहुँचा नहीं जा सकता हो।
केंडल हेल्मसटेटर गेलनर

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

136

जैसा कि मिच और अन्य ने कहा था, आपको एक अपवाद नहीं पकड़ना चाहिए कि आप किसी तरह से निपटने की योजना नहीं बनाते हैं। आपको यह विचार करना चाहिए कि जब आप इसे डिज़ाइन कर रहे हैं तो एप्लिकेशन व्यवस्थित रूप से अपवादों को कैसे संभाल रहा है। यह आमतौर पर अमूर्तताओं के आधार पर त्रुटि से निपटने की परतों की ओर जाता है - उदाहरण के लिए, आप अपने डेटा एक्सेस कोड में सभी एसक्यूएल से संबंधित त्रुटियों को संभालते हैं ताकि डोमेन ऑब्जेक्ट्स के साथ बातचीत करने वाले एप्लिकेशन का हिस्सा इस तथ्य के संपर्क में न हो कि हुड के नीचे एक DB कहीं है।

कुछ संबंधित कोड महक हैं जो आप निश्चित रूप से "हर जगह सब कुछ पकड़" गंध के अलावा बचना चाहते हैं ।

  1. "कैच, लॉग, रिथ्रो" : यदि आप स्कोप आधारित लॉगिंग चाहते हैं, तो एक वर्ग लिखें जो अपने विनाशकारी में लॉग स्टेटमेंट का उत्सर्जन करता है जब स्टैक एक अपवाद (अला std::uncaught_exception()) के कारण अनियंत्रित होता है । आपको बस इतना करने की आवश्यकता है कि आप जिस क्षेत्र में रुचि रखते हैं, उस क्षेत्र में लॉगिंग का उदाहरण घोषित करें और वॉइला, आपके पास लॉगिंग है और कोई अनावश्यक try/ catchतर्क नहीं है।

  2. "कैच, थ्रो ट्रांसलेट" : यह आमतौर पर एक अमूर्त समस्या की ओर इशारा करता है। जब तक आप एक फ़ेडरेटेड समाधान को लागू नहीं कर रहे हैं, जहाँ आप कई विशिष्ट अपवादों को एक और अधिक सामान्य में अनुवाद कर रहे हैं, तो आपके पास शायद अमूर्तता की एक अनावश्यक परत है ... और यह मत कहो कि "मुझे कल इसकी आवश्यकता हो सकती है"

  3. "कैच, क्लीनअप, रीथ्रो" : यह मेरे पालतू जानवरों में से एक है। यदि आप इसमें से बहुत कुछ देखते हैं, तो आपको रिसोर्स एक्विजिशन को इनिशियलाइज़ेशन तकनीकों को लागू करना चाहिए और क्लीनअप वाले हिस्से को चौकीदार ऑब्जेक्ट इंस्टेंस के डिस्ट्रक्टर में रखना चाहिए ।

मुझे लगता है कि कोड की समीक्षा के लिए एक अच्छा लक्ष्य होने के लिए try/ catchब्लॉक के साथ लिटरेड कोड है। यह इंगित करता है कि या तो अपवाद हैंडलिंग अच्छी तरह से समझा नहीं गया है या कोड एक अम्बा बन गया है और रिफैक्टिंग की गंभीर आवश्यकता है।


6
# 1 मेरे लिए नया है। उसके लिए +1। इसके अलावा, मैं # 2 के लिए एक सामान्य अपवाद को नोट करना चाहूंगा, यदि आप एक पुस्तकालय डिजाइन कर रहे हैं, तो अक्सर आप अपने पुस्तकालय इंटरफ़ेस द्वारा निर्दिष्ट कुछ अपवादों में आंतरिक अपवादों का अनुवाद करना चाहेंगे ताकि युग्मन को कम किया जा सके (यह वही हो सकता है जो आपका मतलब है "फेडरेटेड सॉल्यूशन" द्वारा, लेकिन मैं उस शब्द से परिचित नहीं हूं)।
rmeador

3
असल में आपने क्या कहा: parashift.com/c++-faq-lite/exception.html#faq-17.13
Björn Pollex

1
# 2, जहां यह कोड-गंध नहीं है, लेकिन समझ में आता है, पुराने अपवाद को एक नेस्टेड के रूप में रखकर बढ़ाया जा सकता है।
डेडुप्लिकेटर

1
# 1: std :: uncaught_exception () के बारे में आपको बताता है कि उड़ान में कोई अनकहा अपवाद नहीं है, लेकिन AFAIK केवल एक पकड़ () खंड आपको यह निर्धारित करने देता है कि वास्तव में क्या अपवाद है। इसलिए जब आप इस तथ्य को लॉग कर सकते हैं कि आप किसी अपवाद को छोड़कर किसी दायरे से बाहर निकल रहे हैं, तो केवल एक संलग्नक कोशिश / कैच आपको अपने विवरण को लॉग करने देता है। सही बात?
जेरेमी

@ जेरेमी - आप सही हैं। जब मैं अपवाद को संभालता हूं तो मैं आमतौर पर अपवाद विवरण लॉग करता हूं। हस्तक्षेप करने वाले तख्ते का एक निशान होना बहुत उपयोगी है। आपको आमतौर पर थ्रेड आइडेंटिफ़ायर या कुछ पहचान के संदर्भ के साथ-साथ लॉग लाइनों को सहसंबंधित करने की आवश्यकता होती है। मैंने Loggerइसी तरह की एक कक्षा का उपयोग किया था जिसमें log4j.Loggerहर लॉग लाइन में थ्रेड आईडी शामिल थी और एक अपवाद सक्रिय होने पर विध्वंसक में चेतावनी उत्सर्जित करता था।
डी। शॉले

48

क्योंकि अगला सवाल "मैंने एक अपवाद पकड़ा है, मैं आगे क्या करूं?" आप क्या करेंगे? यदि आप कुछ नहीं करते हैं - यह त्रुटि छिपाना है और जो भी हुआ उसे खोजने के लिए कार्यक्रम बिना किसी अवसर के "बस काम नहीं" कर सकता है। आपको यह समझने की जरूरत है कि अपवाद को पकड़ने के बाद आप क्या करेंगे और यदि आप जानते हैं तो केवल पकड़ सकते हैं।


29

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

यह तीन कारणों से अच्छा है: यह आसान है क्योंकि आपके पास त्रुटि की रिपोर्ट करने के लिए एक ही स्थान है: SaveDocument()कैच ब्लॉक (ओं)। सभी उप-विधियों के दौरान इसे दोहराने की कोई आवश्यकता नहीं है, और यह वह है जो आप वैसे भी चाहते हैं: उपयोगकर्ता को किसी चीज़ के बारे में एक उपयोगी निदान देने के लिए एक एकल स्थान जो गलत हो गया।

जब भी अपवाद फेंका जाता है, तो दो को रद्द कर दिया जाता है। प्रत्येक उप-विधि के साथ कोशिश को पकड़ने, अगर एक अपवाद फेंक दिया जाता है, तो आप में है कि विधि का कैच ब्लॉक, निष्पादन पत्ते कार्य करने के लिए मिलता है, और यह पर किया जाता है के माध्यम से SaveDocument()। अगर कुछ पहले से ही गलत हो गया है तो आप संभवतया वहीं रुक जाना चाहते हैं।

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

int ret = SaveFirstSection();

if (ret == FAILED)
{
    /* some diagnostic */
    return;
}

ret = SaveSecondSection();

if (ret == FAILED)
{
    /* some diagnostic */
    return;
}

ret = SaveThirdSection();

if (ret == FAILED)
{
    /* some diagnostic */
    return;
}

यहाँ बताया गया है कि अपवादों के साथ कैसे लिखा जा सकता है:

// these throw if failed, caught in SaveDocument's catch
SaveFirstSection();
SaveSecondSection();
SaveThirdSection();

अब यह बहुत स्पष्ट है कि क्या हो रहा है।

नोट अपवाद सुरक्षित कोड अन्य तरीकों से लिखने के लिए मुश्किल हो सकता है: यदि कोई अपवाद फेंका गया है, तो आप किसी भी मेमोरी को लीक नहीं करना चाहते हैं। सुनिश्चित करें कि आप RAII , STL कंटेनरों, स्मार्ट पॉइंटर्स और अन्य वस्तुओं के बारे में जानते हैं जो विध्वंसक में अपने संसाधनों को मुक्त करते हैं, क्योंकि अपवादों से पहले वस्तुओं को हमेशा नष्ट किया जाता है।


2
शानदार उदाहरण। यूप, तार्किक इकाइयों में, यथासंभव 'ट्रांजैक्शनल' ऑपरेशन जैसे कि लोड / सेव / आदि के रूप में उच्च पकड़। दोहराव से भरे कोड के मुकाबले कुछ भी बुरा नहीं लगता, निरर्थक try- catchकुछ अलग संदेश के साथ कुछ त्रुटि के प्रत्येक अलग-अलग क्रमांकन को फ़्लैग करने का प्रयास, जब वास्तव में उन्हें सभी को एक समान समाप्त करना चाहिए: लेनदेन या प्रोग्राम विफलता और निकास! यदि एक अपवाद-योग्य विफलता होती है, तो मैं अधिकांश उपयोगकर्ताओं को दांव लगाना चाहता हूं कि वे क्या करना चाहते हैं या कम से कम, इसके बारे में संदेश के 10 स्तरों से निपटने के बिना अकेले छोड़ दिया जाए।
अंडरस्कोर_ड

बस यह कहना चाहता था कि यह सबसे अच्छा "जल्दी फेंकना, देर से पकड़ना" है जो मैंने कभी पढ़ा है: संक्षिप्त करें और उदाहरण आपके बिंदुओं को पूरी तरह से दर्शाते हैं। धन्यवाद!
corderazo00

27

हर्ब सटर ने इस समस्या के बारे में यहां लिखा है । पढ़ने के लिए निश्चित रूप से।
एक टीज़र:

"लेखन-अपवाद-सुरक्षित कोड मूल रूप से सही स्थानों पर 'कोशिश' और 'कैच' लिखने के बारे में है।" चर्चा करें।

स्पष्ट रूप से कहें, तो यह कथन अपवाद सुरक्षा की मूलभूत गलतफहमी को दर्शाता है। अपवाद त्रुटि रिपोर्टिंग का सिर्फ एक और रूप है, और हम निश्चित रूप से जानते हैं कि त्रुटि-सुरक्षित कोड लिखना केवल इस बारे में नहीं है कि रिटर्न कोड की जांच कहां की जाए और त्रुटि की स्थिति को कैसे संभालें।

दरअसल, यह पता चलता है कि अपवाद सुरक्षा शायद ही कभी 'कोशिश' और 'कैच' लिखने के बारे में है - और शायद ही कभी बेहतर हो। इसके अलावा, यह कभी न भूलें कि अपवाद सुरक्षा कोड के डिज़ाइन के एक टुकड़े को प्रभावित करती है; यह सिर्फ एक बाद की बात नहीं है जिसे कुछ अतिरिक्त कैच स्टेटमेंट के साथ लिया जा सकता है जैसे कि सीज़निंग के लिए।


15

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

उदाहरण के लिए, उस प्रश्न में जो आपके प्रश्न को जन्म देता है, प्रश्नकर्ता पूछता है कि क्या lexical_castपूर्णांक से स्ट्रिंग के लिए अपवादों को अनदेखा करना सुरक्षित है । ऐसे कलाकारों को कभी असफल नहीं होना चाहिए। यदि यह विफल रहा, तो कार्यक्रम में कुछ गलत हो गया है। उस स्थिति को ठीक करने के लिए आप संभवतः क्या कर सकते हैं? यह शायद कार्यक्रम को मरने देना ही सबसे अच्छा है, क्योंकि यह ऐसी स्थिति में है जिस पर भरोसा नहीं किया जा सकता है। तो अपवाद को नहीं संभालना सबसे सुरक्षित काम हो सकता है।


12

यदि आप हमेशा अपवाद को तुरंत एक विधि के कॉलर में संभालते हैं जो अपवाद को फेंक सकता है, तो अपवाद बेकार हो जाते हैं, और आप त्रुटि कोड को बेहतर बना सकते हैं।

अपवादों की पूरी बात यह है कि उन्हें कॉल चेन में हर तरीके को संभालने की जरूरत नहीं है।


9

मैंने जो सबसे अच्छी सलाह सुनी है वह यह है कि आपको केवल उन बिंदुओं पर अपवादों को पकड़ना चाहिए जहां आप असाधारण स्थिति के बारे में समझदारी से कुछ कर सकते हैं, और यह "पकड़, लॉग और रिलीज़" एक अच्छी रणनीति नहीं है (यदि पुस्तकालयों में कभी-कभी अपरिहार्य है)।


2
@KeithB: मैं इसे दूसरी सबसे अच्छी रणनीति मानूंगा। अगर आप लॉग को दूसरे तरीके से लिख सकते हैं तो बेहतर है।
डेविड थॉर्नले

1
@ कीथबी: यह "लाइब्रेरी में कुछ नहीं से बेहतर" रणनीति है। "पकड़, लॉग, इसके साथ ठीक से व्यवहार करें" जहां संभव हो बेहतर है। (हाँ, मुझे पता है कि यह हमेशा संभव नहीं है।)
डोनल फैलो

6

मैं आपके प्रश्न की मूल दिशा से सहमत हूं कि न्यूनतम स्तर पर यथासंभव कई अपवादों को संभालना है।

मौजूदा उत्तर में से कुछ ऐसे हैं जैसे "आपको अपवाद को संभालने की आवश्यकता नहीं है। कोई और इसे ढेर कर देगा।" मेरे अनुभव के लिए, यह एक बुरा बहाना है जो वर्तमान में विकसित कोड ऑफ कोड पर अपवाद से निपटने के बारे में नहीं सोचता है , अपवाद को किसी और की समस्या को संभालता है।

वितरित विकास में यह समस्या नाटकीय रूप से बढ़ती है, जहां आपको सह-कार्यकर्ता द्वारा कार्यान्वित एक विधि को कॉल करने की आवश्यकता हो सकती है। और फिर आपको यह जानने के लिए विधि कॉल की एक नेस्टेड श्रृंखला का निरीक्षण करना होगा कि वह आपके ऊपर कुछ अपवाद क्यों फेंक रही है, जिसे सबसे गहरी नेस्टेड विधि में बहुत आसान तरीके से नियंत्रित किया जा सकता है।


5

मेरे कंप्यूटर विज्ञान के प्रोफेसर ने मुझे एक बार जो सलाह दी, वह थी: "ट्राय एंड कैच ब्लॉक्स का उपयोग तभी करें जब मानक साधनों का उपयोग करके त्रुटि को संभालना संभव न हो।"

एक उदाहरण के रूप में, उन्होंने हमें बताया कि यदि कोई कार्यक्रम किसी गंभीर मुद्दे पर किसी ऐसी जगह चला गया जहाँ ऐसा करना संभव नहीं है:

int f()
{
    // Do stuff

    if (condition == false)
        return -1;
    return 0;
}

int condition = f();

if (f != 0)
{
    // handle error
}

फिर आपको कोशिश का उपयोग करना चाहिए, ब्लॉकों को पकड़ना चाहिए। जब आप इसे संभालने के लिए अपवादों का उपयोग कर सकते हैं, तो आमतौर पर इसकी अनुशंसा नहीं की जाती है क्योंकि अपवाद महंगे प्रदर्शन के लिहाज से महत्वपूर्ण होते हैं।


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

1
-1 @Sagelika अपवाद से बचने में आपके उत्तर शामिल हैं, इसलिए ट्राइ-कैच की कोई आवश्यकता नहीं है।
विसेंट बोटेट एसेर्बा

3
@ क्रिस्टोफर: रिटर्न कोड के अन्य बड़े नुकसान यह है कि रिटर्न कोड की जांच करना भूल जाना आसान है, और कॉल के बाद समस्या को संभालने के लिए सबसे अच्छी जगह जरूरी नहीं है।
डेविड थॉर्नले

एह, यह निर्भर करता है, लेकिन कई मामलों में (उन लोगों को अलग करना जो जब वास्तव में नहीं करना चाहिए तो फेंक देते हैं), अपवाद इतने सारे कारणों से कोड वापस करने के लिए बेहतर हैं। में सबसे मामलों, विचार है कि अपवाद प्रदर्शन के लिए हानिकारक हैं एक बड़ा ol '[उद्धरण वांछित] है
underscore_d

3

यदि आप प्रत्येक फ़ंक्शन के परिणाम का परीक्षण करना चाहते हैं, तो रिटर्न कोड का उपयोग करें।

अपवाद का उद्देश्य इतना है कि आप अक्सर परिणामों का परीक्षण कर सकते हैं। यह विचार असाधारण (असामान्य, दुर्लभ) स्थितियों को आपके अधिक सामान्य कोड से अलग करना है। यह साधारण कोड क्लीनर और सरल रखता है - लेकिन फिर भी उन असाधारण स्थितियों को संभालने में सक्षम है।

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


2

मैं इस चर्चा में जोड़ना चाहूंगा कि, C ++ 11 के बाद से , यह बहुत मायने रखता है, जब तक कि प्रत्येक catchब्लॉक rethrowअपवाद को छोड़ देता है जब तक कि बिंदु को नियंत्रित नहीं किया जा सकता है। इस तरह एक backtrace उत्पन्न किया जा सकता है । इसलिए मेरा मानना ​​है कि पिछले मत पुराने हैं।

का उपयोग करें std::nested_exceptionऔरstd::throw_with_nested

यह StackOverflow पर वर्णन किया गया है यहाँ और यहाँ है कि यह कैसे प्राप्त करने के लिए।

चूंकि आप इसे किसी भी व्युत्पन्न अपवाद वर्ग के साथ कर सकते हैं, इसलिए आप इस तरह के बैकट्रेस में बहुत सारी जानकारी जोड़ सकते हैं! आप GitHub पर मेरे MWE पर एक नज़र डाल सकते हैं , जहां एक बैकट्रेस कुछ इस तरह दिखेगी:

Library API: Exception caught in function 'api_function'
Backtrace:
~/Git/mwe-cpp-exception/src/detail/Library.cpp:17 : library_function failed
~/Git/mwe-cpp-exception/src/detail/Library.cpp:13 : could not open file "nonexistent.txt"

2

मुझे कई परियोजनाओं और अधिकारियों को निस्तारित करने का "अवसर" दिया गया, जिससे पूरी देव टीम बदल गई क्योंकि ऐप में बहुत अधिक त्रुटियां थीं और उपयोगकर्ता समस्याओं और भाग-दौड़ से थक गए थे। इन कोड आधारों में एप स्तर पर सभी केंद्रीकृत त्रुटि हैंडलिंग थी जैसे शीर्ष मतदान उत्तर विवरण। यदि वह उत्तर सबसे अच्छा अभ्यास है तो यह काम क्यों नहीं किया और पिछली देव टीम को मुद्दों को हल करने की अनुमति देता है? शायद कभी-कभी यह काम नहीं करता है? ऊपर दिए गए उत्तर में यह उल्लेख नहीं किया गया है कि एकल मुद्दों को ठीक करने में देव कितने समय व्यतीत करते हैं। यदि समस्याओं को हल करने का समय प्रमुख मीट्रिक है, तो try..catch ब्लॉकों के साथ इंस्ट्रूमेंटिंग कोड एक बेहतर अभ्यास है।

मेरी टीम ने यूआई को बदलने के बिना समस्याओं को कैसे ठीक किया? सरल, हर विधि का प्रयास के साथ साधन किया गया था..चेक ब्लॉक किया गया और सब कुछ विफलता के बिंदु पर लॉग किया गया था विधि नाम के साथ, विधि पैरामीटर मान एक स्ट्रिंग में समाप्‍त हो गया जिसमें त्रुटि संदेश, त्रुटि संदेश, ऐप का नाम, दिनांक, आदि और संस्करण। इस जानकारी के साथ डेवलपर्स उस अपवाद की पहचान करने के लिए त्रुटियों पर एनालिटिक्स चला सकते हैं जो सबसे अधिक होता है! या त्रुटियों की उच्चतम संख्या के साथ नामस्थान। यह भी मान्य कर सकता है कि एक मॉड्यूल में होने वाली त्रुटि को ठीक से नियंत्रित किया जाता है और कई कारणों से नहीं होता है।

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

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

यह दृष्टिकोण देवों को उत्पादन में रुक-रुक कर मुद्दों को खोजने और ठीक करने देता है! क्या आप उत्पादन में डिबगर के बिना डिबग करना चाहेंगे? या आप परेशान उपयोगकर्ताओं से कॉल लेने और ईमेल प्राप्त करेंगे? यह आपको किसी और को जानने से पहले और ईमेल के बिना, आईएम, या स्लैक के समर्थन में मुद्दों को ठीक करने की अनुमति देता है क्योंकि समस्या को ठीक करने के लिए आवश्यक सब कुछ ठीक है। 95% मुद्दों को पुन: पेश करने की आवश्यकता नहीं है।

ठीक से काम करने के लिए इसे केंद्रीकृत लॉगिंग के साथ जोड़ा जाना चाहिए जो किसी डेटाबेस में नेमस्पेस / मॉड्यूल, क्लास का नाम, विधि, इनपुट और त्रुटि संदेश और स्टोर पर कब्जा कर सकता है, इसलिए यह हाइलाइट करने के लिए एकत्रित किया जा सकता है कि कौन सी विधि सबसे अधिक विफल होती है इसलिए यह हो सकता है पहले तय किया।

कभी-कभी डेवलपर्स कैच ब्लॉक से स्टैक अप अपवाद को फेंकना चुनते हैं, लेकिन यह दृष्टिकोण सामान्य कोड की तुलना में 100 गुना धीमा है जो फेंक नहीं करता है। लॉगिंग के साथ कैच और रिलीज को प्राथमिकता दी जाती है।

इस तकनीक का उपयोग 2 वर्षों में 12 देवों द्वारा विकसित फॉर्च्यून 500 कंपनी में अधिकांश उपयोगकर्ताओं के लिए हर घंटे विफल रहने वाले ऐप को जल्दी से स्थिर करने के लिए किया गया था। इस का उपयोग करते हुए 3000 अलग-अलग अपवादों की पहचान, तय, परीक्षण और 4 महीने में की गई। यह औसतन हर 15 मिनट में औसतन 4 महीने के लिए ठीक हो जाता है।

मैं मानता हूं कि कोड को लिखतने के लिए आवश्यक हर चीज में टाइप करना मजेदार नहीं है और मैं दोहराव वाले कोड को नहीं देखना पसंद करता हूं, लेकिन प्रत्येक विधि में कोड की 4 लाइनों को जोड़ना लंबे समय में इसके लायक है।


1
हर ब्लॉक को लपेटना ओवरकिल जैसा लगता है। यह आपके कोड को जल्दी से फूला हुआ और पढ़ने के लिए दर्दनाक बनाता है। उच्च स्तरों पर एक अपवाद से स्टैकट्रेस लॉग करना आपको दिखाता है कि समस्या कहां हुई और त्रुटि के साथ संयुक्त रूप से आम तौर पर इस पर जाने के लिए पर्याप्त जानकारी है। मुझे इस बात की उत्सुकता होगी कि आपने कहाँ पर्याप्त नहीं पाया। बस इसलिए मैं किसी और का अनुभव हासिल कर सकता हूं।
user441521

1
"अपवाद सामान्य कोड की तुलना में 100 से 1000 गुना धीमा होता है और इसे कभी भी पुनर्जीवित नहीं किया जाना चाहिए" - यह कथन अधिकांश आधुनिक संकलक और हार्डवेयर पर सच नहीं है।
मिच गेहूं

यह ओवरकिल की तरह लगता है और इसके लिए थोड़ी सी टाइपिंग की आवश्यकता होती है, लेकिन उत्पादन में आंतरायिक त्रुटियों सहित सबसे बड़ी त्रुटियों को खोजने और ठीक करने के अपवादों पर विश्लेषण करने का एकमात्र तरीका है। यदि आवश्यक हो तो कैच ब्लॉक विशिष्ट त्रुटियों को संभालता है और इसमें कोड की एक पंक्ति होती है जो लॉग करता है।
user2502917

नहीं, अपवाद बहुत धीमे हैं। विकल्प रिटर्न कोड, ऑब्जेक्ट या चर है। इस ढेर अतिप्रवाह पोस्ट देखें ... "अपवाद कम से कम 30,000 वापसी कोड से गुना धीमी कर रहे हैं" stackoverflow.com/questions/891217/...
user2502917

1

उपरोक्त सलाह के अलावा, व्यक्तिगत रूप से मैं कुछ कोशिश + कैच + फेंक का उपयोग करता हूं; निम्नलिखित कारण से:

  1. अलग-अलग कोडर की सीमा पर, मैं अपने द्वारा लिखे गए कोड में try + catch + throw का उपयोग करता हूं, इससे पहले कि कॉलर द्वारा दूसरों को लिखे गए अपवाद को फेंक दिया जाए, इससे मुझे अपने कोड में उत्पन्न कुछ त्रुटि स्थिति जानने का मौका मिलता है, और यह स्थान उस कोड के बहुत करीब है जो शुरू में अपवाद को फेंक देता है, करीब, कारण खोजने में आसान है।
  2. मॉड्यूल की सीमा पर, हालांकि विभिन्न मॉड्यूल को मेरे समान व्यक्ति लिखा जा सकता है।
  3. सीखना + डिबग उद्देश्य, इस मामले में मैं C ++ में पकड़ (...) का उपयोग करता हूं और C ++ में C # के लिए पकड़ (अपवाद पूर्व), मानक लाइब्रेरी बहुत अधिक अपवाद नहीं फेंकती है, इसलिए यह मामला C ++ में दुर्लभ है। लेकिन सी # में आम जगह, सी # में एक विशाल पुस्तकालय और एक परिपक्व अपवाद पदानुक्रम है, सी # लाइब्रेरी कोड अपवाद के टन को फेंक देता है, सिद्धांत रूप में I (और आपको) आपके द्वारा बुलाए गए फ़ंक्शन से हर अपवाद को जानना चाहिए, और कारण / मामला जानना चाहिए। इन अपवादों को फेंका जा रहा है, और पता है कि उन्हें कैसे संभालना है (पास या पकड़ना और इसे संभालना)। दुर्भाग्य से वास्तव में कोड की एक पंक्ति लिखने से पहले संभावित अपवादों के बारे में सब कुछ जानना बहुत मुश्किल है। इसलिए मैं सभी को पकड़ता हूं और अपने कोड को (उत्पाद वातावरण में) / मुखर संवाद (विकास के माहौल में) में जोर से बोलता हूं, जब कोई भी बदलाव आता है। इस तरह से मैं उत्तरोत्तर हैंडलिंग कोड को उत्तरोत्तर जोड़ता हूं। मुझे पता है कि यह अच्छी सलाह के साथ सामना करता है लेकिन वास्तव में यह मेरे लिए काम करता है और मैं इस समस्या के लिए कोई बेहतर तरीका नहीं जानता।

1

मैं एक और जवाब जोड़ने के लिए मजबूर महसूस करता हूं, हालांकि माइक व्हीट का जवाब मुख्य बिंदुओं को बहुत अच्छी तरह से बताता है। मैं इसे इस तरह से सोचता हूं। जब आपके पास ऐसे तरीके होते हैं जो कई चीजें करते हैं जो आप जटिलता को बढ़ा रहे हैं, इसे जोड़ नहीं रहे हैं।

दूसरे शब्दों में, एक तरीका है कि एक कोशिश पकड़ में लिपटे दो संभावित परिणाम है। आपके पास गैर-अपवाद परिणाम और अपवाद परिणाम हैं। जब आप बहुत सारे तरीकों से काम कर रहे होते हैं तो यह तेजी से समझ से परे हो जाता है।

तेजी से क्योंकि अगर प्रत्येक विधि दो अलग-अलग तरीकों से शाखाएं बनाती हैं, तो हर बार जब आप किसी अन्य विधि को कॉल करते हैं तो आप संभावित परिणामों की पिछली संख्या को बढ़ाते हैं। जब तक आप पाँच विधियाँ कहते हैं, तब तक आप न्यूनतम २५६ परिणामों तक पहुँच सकते हैं। हर एक विधि में एक कोशिश / पकड़ नहीं करने के लिए इसकी तुलना करें और आपके पास केवल एक ही रास्ता है।

यह मूल रूप से है कि मैं इसे कैसे देखता हूं। आपको यह तर्क करने के लिए लुभाया जा सकता है कि किसी भी प्रकार की शाखायें एक ही काम करती हैं लेकिन कोशिश / कैच एक विशेष मामला है क्योंकि आवेदन की स्थिति मूल रूप से अपरिभाषित हो जाती है।

तो संक्षेप में, कोशिश / कैच कोड को समझने के लिए बहुत कठिन बनाते हैं।


-2

आपको अपने कोड के हर हिस्से को कवर करने की कोई आवश्यकता नहीं है try-catchtry-catchब्लॉक का मुख्य उपयोग आपके प्रोग्राम में बग्स / अपवादों को संभालने में त्रुटि करना है। कुछ उपयोग try-catch-

  1. आप इस ब्लॉक का उपयोग कर सकते हैं जहाँ आप एक अपवाद को संभालना चाहते हैं या बस आप कह सकते हैं कि लिखित कोड का ब्लॉक अपवाद को फेंक सकता है।
  2. यदि आप अपने उपयोग के तुरंत बाद अपनी वस्तुओं को निपटाना चाहते हैं, तो आप try-catchब्लॉक का उपयोग कर सकते हैं ।

1
"यदि आप उनके उपयोग के तुरंत बाद अपनी वस्तुओं को निपटाना चाहते हैं, तो आप ट्राइ-कैच ब्लॉक का उपयोग कर सकते हैं।" क्या आपने RAII / न्यूनतम वस्तु जीवनकाल को बढ़ावा देने के लिए इसका इरादा किया था? यदि हां, तो ठीक है, try/ catchcompletelly अलग / कि से ओर्थोगोनल है। यदि आप किसी छोटे दायरे में वस्तुओं का निपटान करना चाहते हैं, तो आप बस एक नया खोल सकते हैं { Block likeThis; /* <- that object is destroyed here -> */ }- जब तक कि आपको वास्तव में किसी चीज की आवश्यकता न हो, तब तक इसे try/ में लपेटने की आवश्यकता नहीं है । catchcatch
अंडरस्कोर_ड

# 2 - अपवाद में ऑब्जेक्ट्स (जो मैन्युअल रूप से बनाए गए थे) मुझे अजीब लगता है, यह कुछ भाषाओं में उपयोगी हो सकता है कोई संदेह नहीं है, लेकिन आम तौर पर आप इसे एक कोशिश में करते हैं / अंत में "कोशिश के अलावा / ब्लॉक को छोड़कर", और नहीं विशेष रूप से अपने आप को छोड़कर ब्लॉक में - चूंकि ऑब्जेक्ट ही पहली जगह में अपवाद का कारण हो सकता है, और इस तरह एक और अपवाद और संभावित रूप से दुर्घटना का कारण बन सकता है।
टीएस
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.