अपवादों को रूढ़िवादी रूप से क्यों इस्तेमाल किया जाना चाहिए?


80

मैं अक्सर लोगों को कहता / सुनता हूं कि अपवादों का उपयोग केवल शायद ही कभी किया जाना चाहिए, लेकिन कभी भी क्यों नहीं समझाएं। हालांकि यह सच हो सकता है, औचित्य सामान्य रूप से एक glib है: "इसे एक कारण के लिए एक अपवाद कहा जाता है" , जो मुझे, एक स्पष्टीकरण के प्रकार लगता है जिसे कभी भी एक सम्मानित प्रोग्रामर / इंजीनियर द्वारा स्वीकार नहीं किया जाना चाहिए।

समस्याओं की एक श्रृंखला है जिसे हल करने के लिए एक अपवाद का उपयोग किया जा सकता है। नियंत्रण प्रवाह के लिए उनका उपयोग करना नासमझी क्यों है? उनके उपयोग के साथ असाधारण रूढ़िवादी होने के पीछे दर्शन क्या है? शब्दार्थ? प्रदर्शन? जटिलता? सौंदर्यशास्त्र? कन्वेंशन?

मैंने पहले प्रदर्शन पर कुछ विश्लेषण देखा है, लेकिन एक स्तर पर जो कुछ प्रणालियों के लिए प्रासंगिक होगा और दूसरों के लिए अप्रासंगिक।

फिर, मैं जरूरी नहीं असहमत हूं कि उन्हें विशेष परिस्थितियों के लिए बचाया जाना चाहिए, लेकिन मैं सोच रहा हूं कि सर्वसम्मति का तर्क क्या है (यदि ऐसा कुछ मौजूद है)।


2
डुप्लिकेट: stackoverflow.com/questions/1736146/…
jheddings

32
नकल नहीं है। लिंक किए गए उदाहरण के बारे में है कि क्या अपवाद हैंडलिंग बिल्कुल उपयोगी है। यह अपवादों का उपयोग करने और एक अन्य त्रुटि रिपोर्टिंग तंत्र का उपयोग करने के बीच अंतर के बारे में है।
एड्रियन मैकार्थी

1
और कैसे इस बारे में एक stackoverflow.com/questions/1385172/… ?
19

1
कोई आम सहमति नहीं है। अपवादों को फेंकने की "उपयुक्तता" के बारे में विभिन्न लोगों की अलग-अलग राय है, और ये राय आम तौर पर उनके द्वारा विकसित की गई भाषा से प्रभावित होती है। आपने इस प्रश्न को C ++ से टैग किया है, लेकिन मुझे संदेह है कि अगर आपने इसे जावा के साथ टैग किया तो आपको अलग-अलग राय मिलेगी।
चार्ल्स साल्विया

5
नहीं, यह विकी नहीं होना चाहिए। यहां जवाब के लिए विशेषज्ञता की आवश्यकता होती है और प्रतिनिधि के साथ पुरस्कृत किया जाना चाहिए।
बोबोबो

जवाबों:


92

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

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

सीधे अपने सवाल का जवाब। अपवादों का उपयोग शायद ही कभी किया जाना चाहिए क्योंकि असाधारण स्थितियां दुर्लभ हैं और अपवाद महंगे हैं।

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

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

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

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

नियंत्रण प्रवाह के लिए उनका उपयोग करना नासमझ क्यों है?

क्योंकि अपवाद सामान्य "नियंत्रण प्रवाह" को बाधित करते हैं। आप एक अपवाद को उठाते हैं और प्रोग्राम के सामान्य निष्पादन को संभावित रूप से असंगत स्थिति में वस्तुओं को छोड़ दिया जाता है और कुछ खुले संसाधनों को अधूरा छोड़ दिया जाता है। निश्चित रूप से, C # का उपयोग करने का विवरण है, जो यह सुनिश्चित करेगा कि वस्तु का उपयोग निकाय से फेंके जाने पर भी वस्तु का निपटान किया जाएगा। लेकिन हमें भाषा से फिलहाल के लिए अमूर्त कर दें। मान लीजिए कि ढांचा आपके लिए वस्तुओं का निपटान नहीं करेगा। आप इसे मैन्युअली करें। आपके पास अनुरोध करने और संसाधनों और स्मृति को कैसे मुक्त करने के लिए कुछ प्रणाली है। आपके पास सिस्टम-वाइड है, जो वस्तुओं और संसाधनों को किन स्थितियों में मुक्त करने के लिए जिम्मेदार है। आपके पास बाहरी पुस्तकालयों से निपटने के नियम हैं। यह बहुत अच्छा काम करता है यदि प्रोग्राम सामान्य ऑपरेशन फ्लो का अनुसरण करता है। लेकिन अचानक निष्पादन के बीच में आप एक अपवाद फेंक देते हैं। आधे संसाधनों को छोड़ दिया गया है। अभी आधे का भी अनुरोध नहीं किया गया है। यदि ऑपरेशन का मतलब लेन-देन करना था तो अब यह टूट गया है। संसाधनों को संभालने के लिए आपके नियम काम नहीं करेंगे क्योंकि संसाधनों को मुक्त करने के लिए जिम्मेदार उन कोड भागों को केवल निष्पादित नहीं किया जाएगा। यदि कोई अन्य व्यक्ति उन संसाधनों का उपयोग करना चाहता था, जो उन्हें असंगत स्थिति में पा सकते हैं और दुर्घटना भी कर सकते हैं क्योंकि वे इस विशेष स्थिति का अनुमान नहीं लगा सकते हैं।

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

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


5
यदि आप एक फ़ंक्शन की तुलना करते हैं जो एक अपवाद बनाम फ़ंक्शन को फेंकता है जो एक त्रुटि कोड देता है, तो स्टैक अनइंडिंग एक ही होगा जब तक कि मैं कुछ याद नहीं कर रहा हूं।
कैटस्कुल

9
@ कैटस्कुल: जरूरी नहीं। एक फ़ंक्शन रिटर्न, तत्काल कॉलर को सीधे नियंत्रण लौटाता है। मौजूदा कॉल स्टैक की संपूर्णता में उस अपवाद प्रकार (या बेस क्लास या "...") के लिए पहला कैच हैंडलर के लिए एक अपवादित अपवाद रिटर्न नियंत्रण को नियंत्रित करता है।
जौन-हॉनसन

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

5
@ जों: यह केवल तभी होगा जब इसे अनकैप्ड किया गया था और त्रुटि हैंडलिंग तक पहुंचने के लिए अधिक स्कोप से बचने की आवश्यकता थी। रिटर्न मानों का उपयोग करते हुए उसी मामले में, (और कई स्कोप के माध्यम से नीचे पारित होने की आवश्यकता भी होती है) स्टैक अनइंडिंग की समान मात्रा होती है।
कैटस्कुल

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

61

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

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

कंस्ट्रक्टर्स

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

एक अपवाद को फेंकने का एकमात्र विकल्प जब एक निर्माता सफल नहीं हो सकता है, तो मान्य "शून्य" या ज़ोंबी राज्यों की अनुमति देने के लिए वर्ग की मूल परिभाषा ("वर्ग अपरिवर्तनीय") को संशोधित करना और इस तरह एक ज़ोंबी का निर्माण करके निर्माता को "सफल" होने दें। ।

ज़ोंबी उदाहरण

इस ज़ोंबी संशोधन का एक उदाहरण std :: ifstream है , और इसका उपयोग करने से पहले आपको हमेशा इसकी स्थिति की जांच करनी चाहिए। क्योंकि std :: string , उदाहरण के लिए, आपको हमेशा यह गारंटी नहीं दी जाती है कि आप इसे निर्माण के तुरंत बाद उपयोग कर सकते हैं। कल्पना करें कि क्या आपको इस तरह के उदाहरण के रूप में कोड लिखना है, और यदि आप ज़ोंबी राज्य की जांच करना भूल गए हैं, तो आप या तो चुपचाप गलत परिणाम प्राप्त करेंगे या अपने कार्यक्रम के अन्य हिस्सों को भ्रष्ट करेंगे:

string s = "abc";
if (s.memory_allocation_succeeded()) {
  do_something_with(s); // etc.
}

यहां तक ​​कि उस विधि का नामकरण इस बात का एक अच्छा उदाहरण है कि कैसे आप एक स्थिति स्ट्रिंग के लिए वर्ग के अपरिवर्तनीय और इंटरफ़ेस को संशोधित करना चाहिए और न ही भविष्यवाणी कर सकते हैं और न ही संभाल सकते हैं।

इनपुट उदाहरण को मान्य करना

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

// boost::lexical_cast<int>() is the parsing function here
void show_square() {
  using namespace std;
  assert(cin); // precondition for show_square()
  cout << "Enter a number: ";
  string line;
  if (!getline(cin, line)) { // EOF on cin
    // error handling omitted, that EOF will not be reached is considered
    // part of the precondition for this function for the sake of example
    //
    // note: the below Python version throws an EOFError from raw_input
    //  in this case, and handling this situation is the only difference
    //  between the two
  }
  int n;
  try {
    n = boost::lexical_cast<int>(line);
    // lexical_cast returns an int
    // if line == "abc", it obviously cannot meet that postcondition
  }
  catch (boost::bad_lexical_cast&) {
    cout << "I can't do that, Dave.\n";
    return;
  }
  cout << n * n << '\n';
}

दुर्भाग्य से, यह दो उदाहरण दिखाता है कि C ++ की स्कूपिंग के लिए आपको RAII / SBRM को कैसे तोड़ना है। पायथन में एक उदाहरण है जिसमें वह समस्या नहीं है और कुछ ऐसा दिखाता है जो मेरी इच्छा है कि C ++ के पास है - प्रयास करें:

# int() is the parsing "function" here
def show_square():
  line = raw_input("Enter a number: ") # same precondition as above
  # however, here raw_input will throw an exception instead of us
  # using assert
  try:
    n = int(line)
  except ValueError:
    print "I can't do that, Dave."
  else:
    print n * n

पूर्व शर्त

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

विशेष रूप से, एसटीडी के विपरीत :: लॉजिक_रोर और एसटी :: रनटाइम_रोर शाखाओं की स्टडलिब अपवाद हॉररसे। पूर्व का उपयोग अक्सर पूर्व-उल्लंघन के उल्लंघन के लिए किया जाता है, जबकि उत्तरार्द्ध बाद के उल्लंघन के लिए अधिक अनुकूल है।


5
निर्णायक उत्तर, लेकिन आप मूल रूप से केवल एक नियम बता रहे हैं, और एक तर्क प्रदान नहीं कर रहे हैं। क्या आपका तर्कसंगत है: कन्वेंशन और शैली?
कैटस्कुल

6
+1। यह इस तरह से है कि अपवादों का उपयोग किया गया था, और इस तरह से उनका उपयोग वास्तव में कोड (IMHO) की पठनीयता और पुन: प्रयोज्य में सुधार करता है।
डैनियल प्राइडेन

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

9
+1। प्री / पोस्ट की स्थिति सबसे अच्छी व्याख्या है जो मैंने कभी सुनी है।
KitsuneYMG

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

40

  1. कर्नेल (सिस्टम) सिग्नल इंटरफेस को प्रबंधित करने के लिए महंगी कर्नेल कॉल (या अन्य सिस्टम एपीआई इनवोकेशन)
  2. विश्लेषण करने के लिए मुश्किल बयान
    की कई समस्याएंgotoअपवादों पर लागू होती हैं। वे कई रूटीन और स्रोत फ़ाइलों में कोड की संभावित बड़ी मात्रा में कूदते हैं। मध्यवर्ती स्रोत कोड को पढ़ने से यह हमेशा स्पष्ट नहीं होता है। (यह जावा में है)
  3. हमेशा इंटरमीडिएट कोड द्वारा प्रत्याशित नहीं किया
    जाता है जो कोड ओवर जंप हो जाता है या मन में अपवाद से बाहर निकलने की संभावना के साथ नहीं लिखा जा सकता है। यदि मूल रूप से ऐसा लिखा गया है, तो शायद इसे ध्यान में नहीं रखा गया है। सोचो: मेमोरी लीक, फाइल डिस्क्रिप्टर लीक, सॉकेट लीक, कौन जानता है?
  4. रखरखाव संबंधी जटिलताएँ
    कोड को बनाए रखना कठिन है जो प्रसंस्करण अपवादों के आसपास कूदता है।

24
+1, सामान्य तौर पर अच्छे कारण। लेकिन ध्यान दें कि स्टैक अनइंडिंग और डिस्ट्रक्टर्स की कॉलिंग की लागत (कम से कम) किसी भी कार्यात्मक समकक्ष त्रुटि से निपटने वाले तंत्र द्वारा भुगतान की जाती है, जैसे कि सी में परीक्षण कोड और त्रुटि कोड वापस करके
j_random_hacker

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

14
जूलियन: j_random की टिप्पणी बताती है कि कोई तुलनात्मक बचत नहीं है: int f() { char* s = malloc(...); if (some_func() == error) { free(s); return error; } ... }आपको स्टैक को खोलना है चाहे आप इसे मैन्युअल रूप से करें या अपवादों के माध्यम से। आप से निपटने के कोई त्रुटि के लिए अपवाद का उपयोग कर तुलना नहीं कर सकते सब पर

14
1. महंगा: समयपूर्व अनुकूलन सभी बुराई की जड़ है। 2. विश्लेषण करना मुश्किल: त्रुटि वापसी कोड की नेस्टेड परतों की तुलना में? मैं आदरपूर्वक असहमत हूं। 3. हमेशा मध्यवर्ती कोड से प्रत्याशित नहीं: नेस्टेड परतों की तुलना में हमेशा त्रुटियों से निपटने और अनुवाद करने में त्रुटि नहीं होती है? दोनों पर न्यूबिज फेल है। 4. रखरखाव जटिलताओं: कैसे? क्या निर्भरताएं त्रुटि कोड द्वारा मध्यस्थता को बनाए रखने में आसान हैं? ... लेकिन यह उन क्षेत्रों में से एक लगता है, जहां या तो स्कूल के डेवलपर्स को एक-दूसरे के तर्कों को स्वीकार करने में कठिनाई होती है। किसी भी चीज़ की तरह, त्रुटि से निपटने का डिज़ाइन एक ट्रेडऑफ़ है।
पौंटस गग्गे

1
मैं मानूंगा कि यह एक जटिल मामला है और यह सामान्यता के साथ सटीक उत्तर देना कठिन है। लेकिन ध्यान रखें कि मूल प्रश्न ने केवल यह पूछा कि अपवाद-विरोधी सलाह क्यों दी गई, न कि समग्र सर्वोत्तम अभ्यास के स्पष्टीकरण के लिए।
डिजिटलरॉस

22

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


5
प्रवाह नियंत्रण के अलावा किसी भी उद्देश्य के लिए एक अपवाद का उपयोग करना कैसे संभव है? एक असाधारण स्थिति में भी, वे अभी भी एक प्रवाह नियंत्रण तंत्र हैं, जिसके परिणाम आपके कोड की स्पष्टता के लिए हैं (यहाँ माना जाता है: समझ से बाहर)। मुझे लगता है कि आप अपवादों का उपयोग कर सकते हैं लेकिन प्रतिबंध लगा सकते हैं catch, हालांकि उस स्थिति में आप लगभग std::terminate()खुद को ही बुला सकते हैं। कुल मिलाकर, यह तर्क मुझे "अपवादों का उपयोग कभी नहीं" कहने के लिए लगता है, बजाय "केवल अपवादों का उपयोग करें शायद ही कभी"।
स्टीव जेसप

5
फंक्शन के अंदर रिटर्न स्टेटमेंट आपको फंक्शन से बाहर ले जाता है। अपवाद आपको ले जाता है जो जानता है कि कितनी परतें हैं - यह पता लगाने का कोई सरल तरीका नहीं है।

2
स्टीव: मैं आपकी बात समझता हूं, लेकिन मेरा मतलब यह नहीं है। अप्रत्याशित परिस्थितियों के लिए अपवाद ठीक हैं। कुछ लोग उन्हें "शुरुआती रिटर्न" के रूप में दुरुपयोग करते हैं, शायद कुछ प्रकार के स्विच स्टेटमेंट के रूप में भी।
एरच किट्ज़म्यूलर 20

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

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

16

अपवाद आपके कार्यक्रम की स्थिति के बारे में तर्क करना कठिन बनाते हैं। उदाहरण के लिए C ++ में, आपको यह सुनिश्चित करने के लिए अतिरिक्त सोच-विचार करना होगा कि आपके कार्य दृढ़ता से सुरक्षित हैं, यदि आपको उनकी आवश्यकता नहीं है, तो आपको करना होगा।

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

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

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

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

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


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

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

एक बार जब आप एक संकलक का उपयोग करते हैं जो स्टैक को खोलना नहीं है (या अन्यथा इसमें अपवादों को अक्षम करें), तो यह तकनीकी रूप से बोल रहा है, अब C ++ :)
पावेल मिनावे

बिना किसी अपवाद के स्टैक को खोलना नहीं है, मेरा मतलब है।
स्टीव जेसप

यह कैसे पता चलता है कि जब तक यह स्टैक को पकड़ ब्लॉक नहीं दिखाता है तब तक यह अनकहा नहीं है?
jmucchiello

11

वास्तव में कोई आम सहमति नहीं है। पूरा मुद्दा कुछ हद तक व्यक्तिपरक है, क्योंकि अपवाद को फेंकने की "उपयुक्तता" अक्सर भाषा के मानक पुस्तकालय के भीतर मौजूदा प्रथाओं द्वारा सुझाई जाती है। C ++ मानक पुस्तकालय अपवादों को बहुत कम बार कहता है, जावा मानक पुस्तकालय, जो लगभग हमेशा अपवादों को प्राथमिकता देता है, यहां तक ​​कि अपेक्षित त्रुटियों जैसे कि अमान्य उपयोगकर्ता इनपुट (जैसे Scanner.nextInt) के लिए भी। मेरा मानना ​​है कि डेवलपर की राय को महत्वपूर्ण रूप से प्रभावित करता है जब अपवाद को फेंकना उचित होता है।

C ++ प्रोग्रामर के रूप में, मैं व्यक्तिगत रूप से बहुत ही "असाधारण" परिस्थितियों के लिए अपवादों को आरक्षित करना पसंद करता हूं, उदाहरण के लिए मेमोरी से बाहर, डिस्क-स्पेस से, सर्वनाश हुआ, आदि। लेकिन मैं जोर नहीं देता कि यह करने का पूर्ण सही तरीका है चीजें।


2
मुझे लगता है कि एक तरह की आम सहमति है, लेकिन शायद यह सहमति ध्वनि तर्क के बजाय सम्मेलन पर अधिक आधारित है। केवल असाधारण परिस्थितियों के लिए अपवादों का उपयोग करने के लिए ध्वनि कारण हो सकते हैं, लेकिन अधिकांश डेवलपर्स वास्तव में कारणों से अवगत नहीं हैं।
20

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

2
+1। कोई कठिन और तेज़ नियम नहीं हैं, बस कन्वेंशन - लेकिन यह दूसरों के सम्मेलनों का पालन करने के लिए उपयोगी है जो आपकी भाषा का उपयोग करते हैं, क्योंकि यह प्रोग्रामर के लिए एक-दूसरे के कोड को समझना आसान बनाता है।
j_random_hacker 3

1
"सर्वनाश हुआ" - कभी भी अपवादों को ध्यान में न रखें, अगर कुछ भी यूबी को सही ठहराता है, तो ;-)
स्टीव जेसप

3
Catskul: प्रोग्रामिंग के लगभग सभी सम्मेलन है। तकनीकी रूप से, हमें अपवादों की आवश्यकता नहीं है, या वास्तव में बहुत अधिक है। यदि इसमें एनपी-पूर्णता, बिग-ओ / थीटा / लिटिल-ओ, या यूनिवर्सल ट्यूरिंग मशीनें शामिल नहीं हैं, तो यह संभवतः सम्मेलन है। :-)
केन

7

मुझे नहीं लगता, कि अपवादों का उपयोग शायद ही कभी किया जाना चाहिए। परंतु।

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

यदि आप अपवादों का बड़े पैमाने पर उपयोग करने जा रहे हैं, तो:

  • अपने लोगों को यह सिखाने के लिए तैयार रहें कि अपवाद सुरक्षा क्या है
  • आपको कच्चे स्मृति प्रबंधन का उपयोग नहीं करना चाहिए
  • बड़े पैमाने पर RAII का उपयोग करें

दूसरी ओर, मजबूत टीम के साथ नई परियोजनाओं में अपवादों का उपयोग करके कोड क्लीनर, बनाए रखने में आसान और इससे भी तेज हो सकता है:

  • आप त्रुटियों को याद नहीं करेंगे या अनदेखा नहीं करेंगे
  • आप वास्तव में कम स्तर पर गलत कोड के साथ क्या करना है, यह जानने के बिना, रिटर्न कोड के उस चेक को लिखना नहीं है
  • जब आपको अपवाद-सुरक्षित कोड लिखने के लिए मजबूर किया जाता है, तो यह अधिक संरचित हो जाता है

1
मुझे विशेष रूप से इस तथ्य का आपका उल्लेख पसंद आया कि "सभी टीमें ... अपवादों का उपयोग करने के लिए तैयार नहीं हैं"। अपवाद निश्चित रूप से कुछ ऐसा है जो करना आसान लगता है, लेकिन सही करने के लिए बेहद कठिन हैं , और यह वही है जो उन्हें खतरनाक बनाता है।
j_random_hacker

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

7

EDIT 11/20/2009 :

मैं प्रबंधित कोड प्रदर्शन को बेहतर बनाने के लिए MSDN के इस लेख को पढ़ रहा था और इस हिस्से ने मुझे इस प्रश्न की याद दिला दी:

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

बेशक, यह केवल .NET के लिए है, और यह विशेष रूप से उन उच्च-प्रदर्शन अनुप्रयोगों को विकसित करने के लिए भी निर्देशित है (जैसे स्वयं); इसलिए यह स्पष्ट रूप से एक सार्वभौमिक सत्य नहीं है। फिर भी, वहाँ हम में से बहुत सारे .NET डेवलपर्स हैं, इसलिए मुझे लगा कि यह ध्यान देने योग्य है।

संपादित करें :

ठीक है, सबसे पहले, चलो एक बात सीधे करें: प्रदर्शन के सवाल पर मेरा किसी से झगड़ा करने का कोई इरादा नहीं है। सामान्य तौर पर, वास्तव में, मैं उन लोगों से सहमत होने के लिए इच्छुक हूं जो मानते हैं कि समय से पहले अनुकूलन एक पाप है। हालाँकि, मुझे सिर्फ दो बिंदु बनाने हैं:

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

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

मेरी बात को समझाने के लिए, निम्नलिखित C # कोड उदाहरणों पर विचार करें।

उदाहरण 1: अमान्य उपयोगकर्ता इनपुट का पता लगाना

यह एक उदाहरण है कि मैं अपवाद दुरुपयोग क्या कहूंगा ।

int value = -1;
string input = GetInput();
bool inputChecksOut = false;

while (!inputChecksOut) {
    try {
        value = int.Parse(input);
        inputChecksOut = true;

    } catch (FormatException) {
        input = GetInput();
    }
}

यह कोड मेरे लिए हास्यास्पद है। बेशक यह काम करता है । उसके साथ किसी की बहस नहीं हुई। लेकिन यह कुछ इस तरह होना चाहिए :

int value = -1;
string input = GetInput();

while (!int.TryParse(input, out value)) {
    input = GetInput();
}

उदाहरण 2: फ़ाइल के अस्तित्व की जाँच करना

मुझे लगता है कि यह परिदृश्य वास्तव में बहुत सामान्य है। यह निश्चित रूप से बहुत अधिक लोगों को "स्वीकार्य" लगता है, क्योंकि यह फ़ाइल I / O से संबंधित है:

string text = null;
string path = GetInput();
bool inputChecksOut = false;

while (!inputChecksOut) {
    try {
        using (FileStream fs = new FileStream(path, FileMode.Open)) {
            using (StreamReader sr = new StreamReader(fs)) {
                text = sr.ReadToEnd();
            }
        }

        inputChecksOut = true;

    } catch (FileNotFoundException) {
        path = GetInput();
    }
}

यह उचित पर्याप्त लगता है, है ना? हम एक फ़ाइल खोलने की कोशिश कर रहे हैं; अगर यह नहीं है, तो हम उस अपवाद को पकड़ लेते हैं और एक अलग फाइल खोलने की कोशिश करते हैं ... इसमें गलत क्या है?

कुछ भी सच नहीं। लेकिन इस विकल्प पर विचार करें, जिसमें कोई अपवाद नहीं है:

string text = null;
string path = GetInput();

while (!File.Exists(path)) path = GetInput();

using (FileStream fs = new FileStream(path, FileMode.Open)) {
    using (StreamReader sr = new StreamReader(fs)) {
        text = sr.ReadToEnd();
    }
}

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

का उपयोग कर try/ catchब्लॉक : 25.455 सेकंड
का उपयोग कर int.TryParse: 1.637 मिलीसेकंड

दूसरे उदाहरण के लिए, मैंने मूल रूप से एक ही काम किया: 10000 यादृच्छिक तारों की एक सूची बनाई, जिनमें से कोई भी एक वैध पथ नहीं था, फिर बहुत ही अंत में एक वैध मार्ग जोड़ा। ये परिणाम थे:

का उपयोग कर try/ catchब्लॉक: 29.989 सेकंड
का उपयोग करना File.Exists: 22.820 मिलीसेकंड

बहुत से लोग इस पर प्रतिक्रिया देते हुए कहते हैं, "हाँ, ठीक है, 10,000 अपवादों को फेंकना और पकड़ना बेहद अवास्तविक है; इससे परिणाम अतिरंजित होते हैं।" बिलकुल यह करता है। एक अपवाद को फेंकने और अपने आप पर खराब इनपुट को संभालने के बीच का अंतर उपयोगकर्ता के लिए ध्यान देने योग्य नहीं है। तथ्य यह है कि अपवादों का उपयोग करते हुए, इन दो मामलों में, 1,000 से 10,000 गुना अधिक वैकल्पिक दृष्टिकोणों की तुलना में धीमा है जो कि केवल पठनीय हैं - यदि ऐसा नहीं है।

इसलिए मैंने GetNine()नीचे दी गई विधि का उदाहरण शामिल किया । ऐसा नहीं है कि यह असहिष्णु रूप से धीमा है या अस्वीकार्य रूप से धीमा है; यह है कि यह धीमी गति से होना चाहिए ... बिना किसी अच्छे कारण के

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


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

ठीक है, शायद यह आपके विशेष रूप से व्यावसायिक परिदृश्य के लिए ठीक है, लेकिन अपेक्षाकृत बोलना , फेंकना / पकड़ना एक तरह से अधिक ओवरहेड का परिचय देता है, कई मामलों में आवश्यक है। आप इसे जानते हैं, मैं इसे जानता हूं: अधिकांश समय , यदि आप प्रोग्राम प्रवाह को नियंत्रित करने के लिए अपवादों का उपयोग कर रहे हैं, तो आप केवल धीमी कोड लिख रहे हैं।

आप यह भी पूछ सकते हैं: यह कोड खराब क्यों है?

private int GetNine() {
    for (int i = 0; i < 10; i++) {
        if (i == 9) return i;
    }
}

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

जब लोग अपवाद के बारे में बात करते हैं तो इसका मतलब है "दुरुपयोग।"


2
"अपवाद हैंडलिंग में भयावह प्रदर्शन है।" - यह एक कार्यान्वयन विवरण है, और सभी भाषाओं के लिए सही नहीं है, और यहां तक ​​कि C ++ के लिए विशेष रूप से, सभी कार्यान्वयनों के लिए।
पावेल मिनाएव

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

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

1
@j_random_hacker: आप सही हैं, GetNineइसका काम ठीक है। मेरा कहना है कि इसका उपयोग करने का कोई कारण नहीं है। ऐसा नहीं है कि यह कुछ करने का "त्वरित और आसान" तरीका है, जबकि अधिक "सही" दृष्टिकोण बहुत अधिक प्रयास करेगा। मेरे अनुभव में, यह अक्सर ऐसा होता है कि "सही" दृष्टिकोण वास्तव में कम प्रयास करेगा, या उसी के बारे में। वैसे भी, मेरे लिए प्रदर्शन ही एकमात्र उद्देश्य है कि क्यों बाएं और दाएं अपवादों का उपयोग हतोत्साहित किया जाता है। इस बात के लिए कि क्या प्रदर्शन हानि "स्थूल रूप से बहुत अधिक है," वास्तव में व्यक्तिपरक है।
डान ताओ

1
@j_random_hacker: आपका पक्ष बहुत दिलचस्प है, और वास्तव में कार्यान्वयन के आधार पर प्रदर्शन हिट के बारे में होम पावेल की बात को प्रेरित करता है। एक बात मुझे बहुत संदेह है कि किसी को एक परिदृश्य मिल सकता है जिसमें अपवाद का उपयोग वास्तव में वैकल्पिक (जहां एक विकल्प मौजूद है, कम से कम, जैसे कि मेरे उदाहरण में) से बेहतर प्रदर्शन करता है।
दान ताओ

6

अपवादों के बारे में अंगूठे के सभी नियम व्यक्तिपरक शब्दों के नीचे आते हैं। आप का उपयोग करने के लिए जब नहीं करने के लिए कठिन और तेजी से परिभाषाएँ प्राप्त करने की उम्मीद करनी चाहिए। "केवल असाधारण परिस्थितियों में"। अच्छी परिपत्र परिभाषा: अपवाद असाधारण परिस्थितियों के लिए हैं।

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

बहुत सारी राय है, और ट्रेडऑफ बनाया जाना है। कोई ऐसी चीज खोजें, जो आपसे बोलती हो, और उसका पालन करें।


6

ऐसा नहीं है कि अपवादों का उपयोग शायद ही कभी किया जाना चाहिए। यह सिर्फ इतना है कि उन्हें केवल असाधारण परिस्थितियों में फेंक दिया जाना चाहिए। उदाहरण के लिए, यदि कोई उपयोगकर्ता गलत पासवर्ड दर्ज करता है, तो यह असाधारण नहीं है।

कारण सरल है: अपवाद अचानक एक फ़ंक्शन से बाहर निकलते हैं, और स्टैक को एक catchब्लॉक तक प्रचारित करते हैं । यह प्रक्रिया बहुत कम्प्यूटेशनल रूप से महंगी है: C ++ अपने अपवाद सिस्टम को "सामान्य" फ़ंक्शन कॉल पर बहुत अधिक ओवरहेड बनाने के लिए बनाता है, इसलिए जब कोई अपवाद उठाया जाता है, तो यह जानने के लिए बहुत काम करना पड़ता है कि कहां जाना है। इसके अलावा, कोड की हर पंक्ति संभवतः एक अपवाद बढ़ा सकती है। यदि हमारे पास कुछ फ़ंक्शन हैं fजो अक्सर अपवादों को उठाते हैं, तो हमें अब हर कॉल के आसपास हमारे try/ catchब्लॉकों का उपयोग करने के लिए ध्यान रखना होगा f। यह एक बहुत बुरा इंटरफ़ेस / कार्यान्वयन युग्मन है।


8
आपने अनिवार्य रूप से "वे एक कारण के लिए अपवाद कहे जाते हैं" को दोहराया है। मैं लोगों को इस बारे में और अधिक पुष्ट करने के लिए देख रहा हूँ।
कैटस्कुल

4
"असाधारण परिस्थितियों" का क्या अर्थ है? व्यवहार में, मेरे प्रोग्राम को खराब उपयोगकर्ता पासवर्ड की तुलना में वास्तविक IOException को अधिक बार हैंडल करना है। इसका मतलब है कि आपको लगता है कि मुझे BadUserPassword को अपवाद बनाना चाहिए , या कि stdlib लोगों को IOException को अपवाद नहीं बनाना चाहिए था ? "बहुत कम्प्यूटेशनल रूप से महंगा" वास्तविक कारण नहीं हो सकता है, क्योंकि मैंने कभी भी एक प्रोग्राम नहीं देखा है (और निश्चित रूप से मेरा नहीं) जिसके लिए किसी भी नियंत्रण तंत्र के माध्यम से एक गलत पासवर्ड से निपटने, एक प्रदर्शन अड़चन थी।
केन

5

मैंने C ++ अपवादों पर एक लेख में इस मुद्दे का उल्लेख किया ।

प्रासंगिक हिस्सा:

लगभग हमेशा, "सामान्य" प्रवाह को प्रभावित करने के लिए अपवादों का उपयोग करना एक बुरा विचार है। जैसा कि हमने पहले ही खंड 3.1 में चर्चा की है, अपवाद अदृश्य कोड पथ उत्पन्न करते हैं। ये कोड पथ यकीनन स्वीकार्य हैं यदि वे केवल त्रुटि हैंडलिंग परिदृश्यों में निष्पादित होते हैं। हालांकि, अगर हम किसी अन्य उद्देश्य के लिए अपवादों का उपयोग करते हैं, तो हमारे "सामान्य" कोड निष्पादन को एक दृश्य और अदृश्य भाग में विभाजित किया गया है और यह कोड को पढ़ने, समझने और विस्तारित करने के लिए बहुत कठिन बनाता है।


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

मैं C से C ++ में भी आया था, लेकिन CI में भी "सामान्य" फ्लो एंड एरर हैंडलिंग में अंतर किया गया। यदि आप फोपेन () कहते हैं, तो एक शाखा है जो सफलता के मामले से संबंधित है और यह "सामान्य" है, और एक जो विफलता के संभावित कारणों से संबंधित है, और वह है त्रुटि से निपटने।
नेमंजा ट्रिफ़ुनोविक

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

1
उदाहरण: आपके पास एक फ़ंक्शन है जहां कुछ करने की आवश्यकता होती है, लेकिन आप अलग-अलग दृष्टिकोणों के पूरे भार का प्रयास करने जा रहे हैं, और आपको नहीं पता कि कौन सफल होगा, और उनमें से प्रत्येक कुछ अतिरिक्त उप-दृष्टिकोणों की कोशिश कर सकते हैं, और जब तक कुछ काम करता है, तब तक। तब मैं तर्क दूंगा कि विफलता "सामान्य" है, और सफलता "असाधारण" है, हालांकि स्पष्ट रूप से त्रुटि नहीं है। सफलता पर एक अपवाद को फेंकना कठिन नहीं है, बल्कि एक भयानक त्रुटि पर एक अपवाद को फेंकने से अधिकांश कार्यक्रमों में है - आप यह सुनिश्चित करते हैं कि कोड के केवल एक बिट को पता है कि आगे क्या करना है, और आप सीधे वहां कूदते हैं।
स्टीव जेसप

1
@onebyone: आपकी दूसरी टिप्पणी वास्तव में एक अच्छी बात है जो मैंने कहीं और नहीं देखी है। मुझे लगता है कि इसका उत्तर यह है कि (जैसा कि आपने प्रभावी रूप से अपने स्वयं के उत्तर में कहा था), त्रुटि स्थितियों के अपवादों का उपयोग करके कई भाषाओं के "मानक प्रथाओं" में अवशोषित किया गया है, भले ही इसके मूल कारणों का पालन करने के लिए एक उपयोगी दिशानिर्देश बना। कर रहे थे कि गुमराह किया गया।
j_random_hacker

5

त्रुटि से निपटने के लिए मेरा दृष्टिकोण यह है कि तीन मूलभूत प्रकार की त्रुटियाँ हैं:

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

विरोधाभास के लिए, अपवाद तब होते हैं जब आपके पास एक समस्या होती है जिससे आप निपट सकते हैं, लेकिन आप उस जगह से नहीं निपट सकते हैं जिसे आप नोटिस करते हैं। आप जिन समस्याओं से निपट नहीं सकते, उन्हें बस कार्यक्रम को मारना चाहिए; समस्याओं को आप अभी दूर कर सकते हैं बस के साथ निपटा जाना चाहिए।


2
आप गलत प्रश्न का उत्तर दे रहे हैं। हम यह नहीं जानना चाहते कि त्रुटि परिदृश्यों से निपटने के लिए हमें अपवादों का उपयोग क्यों करना चाहिए (या नहीं करना चाहिए) - हम यह जानना चाहते हैं कि हमें गैर-त्रुटि वाले परिदृश्यों के लिए उनका उपयोग क्यों करना चाहिए (या नहीं करना चाहिए)।
j_random_hacker

5

मैंने यहाँ कुछ उत्तर पढ़े। मैं अभी भी चकित हूं कि यह सब भ्रम किस बारे में है। मैं इन सभी अपवादों से असहमत हूं == स्पेगेटी कोड। भ्रम के साथ मेरा मतलब है, कि ऐसे लोग हैं, जो C ++ अपवाद हैंडलिंग की सराहना नहीं करते हैं। मैं निश्चित नहीं हूं कि मैंने C ++ अपवाद हैंडलिंग के बारे में कैसे सीखा - लेकिन मैंने मिनटों में निहितार्थ को समझ लिया। यह 1996 के आसपास था और मैं ओएस / 2 के लिए बोरलैंड C ++ कंपाइलर का उपयोग कर रहा था। मुझे कभी भी यह तय करने की समस्या नहीं थी कि अपवादों का उपयोग कब करना है। मैं आमतौर पर C ++ कक्षाओं में फॉलिबल डू-अनडू एक्शन को लपेटता हूं। ऐसी गतिविधियों को पूर्ववत करें:

  • सिस्टम हैंडल को बनाना / नष्ट करना (फाइलों, मेमोरी मैप्स, WIN32 GUI हैंडल, सॉकेट्स आदि के लिए)
  • सेटिंग / परेशान करने वाले हैंडलर
  • स्मृति आवंटित करना / डील करना
  • म्यूटेक्स का दावा / विमोचन
  • incrementing / decrementing एक संदर्भ गणना
  • विंडो दिखाना / छिपाना

वहाँ कार्यात्मक रैपर हैं। सिस्टम कॉल को लपेटने के लिए (जो पूर्व श्रेणी में नहीं आते हैं) C ++ में। जैसे फ़ाइल से / से पढ़ना / लिखना। यदि कुछ विफल होता है, तो एक अपवाद फेंक दिया जाएगा, जिसमें त्रुटि के बारे में पूरी जानकारी है।

फिर विफलता में अधिक जानकारी जोड़ने के लिए अपवादों को पकड़ना / पुनर्विचार करना है।

कुल मिलाकर C ++ अपवाद हैंडलिंग अधिक स्वच्छ कोड की ओर जाता है। कोड की मात्रा में भारी कमी आई है। अंत में एक निर्माणकर्ता का उपयोग करने योग्य संसाधनों को आवंटित करने के लिए किया जा सकता है और इस तरह की विफलता के बाद भी भ्रष्टाचार मुक्त वातावरण बनाए रख सकते हैं।

एक ऐसे वर्गों को जटिल कक्षाओं में श्रृंखलाबद्ध कर सकता है। एक बार किसी सदस्य / बेस ऑब्जेक्ट के एक कंस्ट्रक्टर को एक्सट्रैक्ट किया जाता है, तो कोई भी उस ऑब्जेक्ट के अन्य सभी कंस्ट्रक्टरों (पहले निष्पादित) सफलतापूर्वक निष्पादित कर सकता है, इस पर भरोसा कर सकता है।


3

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

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

यदि कोई क्लाइंट ParseIntस्ट्रिंग के साथ कॉल करता है, और स्ट्रिंग में पूर्णांक नहीं है, तो तत्काल कॉलर संभवतः त्रुटि के बारे में परवाह करता है और जानता है कि इसके बारे में क्या करना है। तो आप ParseInt को इस तरह से कुछ के लिए एक विफलता कोड वापस करने के लिए डिज़ाइन करेंगे।

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

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


1
और फिर भी, जावा में, parseIntवास्तव में है एक अपवाद फेंक देते हैं। इसलिए, मैं कहूंगा कि अपवादों को फेंकने की उपयुक्तता के बारे में राय उनके चुने हुए विकास की भाषा के मानक पुस्तकालयों के भीतर पहले से मौजूद प्रथाओं पर निर्भर है।
चार्ल्स साल्विया

जावा के रनटाइम को वैसे भी सूचनाओं पर नज़र रखनी होती है, जिससे अपवादों को उत्पन्न करना आसान हो जाता है ... c ++ कोड में यह जानकारी हाथों पर नहीं होती है, इसलिए इसे उत्पन्न करने के लिए इसमें एक प्रदर्शन दंड है। इसे हाथ में नहीं रखने से, यह तेज़ / छोटा / अधिक कैश फ्रेंडली आदि हो जाता है। इसके अलावा, जावा कोड में एरे आदि चीज़ों पर डायनामिक जाँच होती है, एक विशेषता c ++ में निहित नहीं है, इसलिए java एक्स्ट्रा क्लास ऑफ़ एक्सेप्टेंस जो कि डेवलपर है पहले से ही कोशिश / पकड़ने वाले ब्लॉक के साथ इन चीजों का बहुत ख्याल रख रहा है, तो क्यों हर व्यक्ति अपवाद का उपयोग नहीं करता है?
एपे-इनोगो

1
@Charles - प्रश्न C ++ के साथ टैग किया गया है, इसलिए मैं उस परिप्रेक्ष्य से उत्तर दे रहा था। मैंने कभी जावा (या C #) प्रोग्रामर को यह कहते नहीं सुना कि अपवाद केवल असाधारण स्थितियों के लिए हैं। सी ++ प्रोग्रामर नियमित रूप से यह कहते हैं, और सवाल यह था कि क्यों।
एड्रियन मैक्कार्थी

1
वास्तव में, सी # अपवाद कहते हैं कि जैसा भी हो, और इसका कारण यह है कि अपवाद .NET में फेंकने के लिए बहुत महंगे हैं (जावा में अधिक से अधिक)।
पावेल मिनाएव

1
@ एड्रियन: सच है, इस सवाल को सी ++ के साथ टैग किया गया है, हालांकि अपवाद हैंडलिंग दर्शन कुछ हद तक भाषा-संवाद है, क्योंकि भाषाएं निश्चित रूप से एक-दूसरे को प्रभावित करती हैं। वैसे भी, Boost.lexical_cast एक अपवाद फेंकता है। लेकिन क्या एक अमान्य स्ट्रिंग वास्तव में "असाधारण" है? यह शायद नहीं है, लेकिन बूस्ट डेवलपर्स ने सोचा कि शांत कास्ट सिंटैक्स होने अपवादों का उपयोग करने के लायक था। यह सिर्फ यह दिखाने के लिए जाता है कि पूरी चीज कितनी व्यक्तिपरक है।
चार्ल्स सल्विया

3

C ++ में कई कारण हैं।

सबसे पहले, यह देखना अक्सर कठिन होता है कि अपवाद कहां से आ रहे हैं (क्योंकि उन्हें लगभग किसी भी चीज से फेंका जा सकता है) और इसलिए कैच ब्लॉक एक COME FROM स्टेटमेंट में से कुछ है। यह GO TO से भी बदतर है, क्योंकि GO में आपको पता है कि आप कहां से आ रहे हैं (स्टेटमेंट, कुछ रैंडम फंक्शन कॉल नहीं) और आप कहां जा रहे हैं (लेबल)। वे मूल रूप से C के सेटजम्प () और लॉन्गजम्प () का संभावित संसाधन-सुरक्षित संस्करण हैं, और कोई भी उनका उपयोग नहीं करना चाहता है।

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

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


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

मुझे यह उत्तर पसंद है लेकिन, पावेल की तरह मुझे नहीं लगता कि दूसरा बिंदु वैध है। जब किसी भी कारण से गुंजाइश खत्म हो जाती है, तो अन्य प्रकार की त्रुटि से निपटने या बस कार्यक्रम जारी रखने सहित, विध्वंसक वैसे भी कहा जाएगा।
कैटस्कुल

प्रवाह के साथ जाने के कारण के रूप में भाषा संस्कृति का उल्लेख करने के लिए +1। यह उत्तर कुछ के लिए असंतोषजनक है, लेकिन यह एक वास्तविक कारण है (और मेरा मानना ​​है कि यह सबसे सटीक कारण है)।
j_random_hacker

@ मान: कृपया मेरी गलत टिप्पणी को अनदेखा करें (अब हटाए गए) यह कहते हुए कि जावा finallyब्लॉक चलाने की गारंटी नहीं है - बेशक वे हैं। मैं जावा finalize()विधि से भ्रमित हो रहा था , जिसे चलाने की गारंटी नहीं है।
j_random_hacker

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

2

यह नियंत्रण प्रवाह के रूप में अपवादों का उपयोग करने का एक बुरा उदाहरण है:

int getTotalIncome(int incomeType) {
   int totalIncome= 0;
   try {
      totalIncome= calculateIncomeAsTypeA();
   } catch (IncorrectIncomeTypeException& e) {
      totalIncome= calculateIncomeAsTypeB();
   }

   return totalIncome;
}

जो बहुत बुरा है, लेकिन आपको लिखना चाहिए:

int getTotalIncome(int incomeType) {
   int totalIncome= 0;
   if (incomeType == A) {
      totalIncome= calculateIncomeAsTypeA();
   } else if (incomeType == B) {
      totalIncome= calculateIncomeAsTypeB();
   }
   return totalIncome;
}

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

अपवादों में कुछ प्रदर्शन दंड भी जुड़े होते हैं, लेकिन प्रदर्शन की समस्याओं को नियम का पालन करना चाहिए: "समय से पहले अनुकूलन सभी बुराई की जड़ है"


एक मामले की तरह लगता है जब जाँच के बजाय अधिक बहुरूपता अच्छा होगा incomeType
सारा वेसल्स

@ सरह हाँ मुझे पता है कि यह अच्छा होगा। यह केवल दृष्टांत उद्देश्यों के लिए है।
एडिसन गुस्तावो मुएंज

3
यह बुरा क्यों है? आपको इसे दूसरा तरीका क्यों लिखना चाहिए? पूछने वाला नियमों के कारणों को जानना चाहता है, नियमों को नहीं। -1।
j_random_hacker

2
  1. रखरखाव: जैसा कि ऊपर लोगों द्वारा उल्लेख किया गया है, एक टोपी के एक बूंद पर अपवादों को फेंकना गोटो का उपयोग करने के समान है।
  2. इंटरऑपरेबिलिटी: यदि आप अपवादों का उपयोग कर रहे हैं, तो आप C / Python मॉड्यूल (कम से कम आसानी से नहीं) के साथ C ++ पुस्तकालयों को इंटरफ़ेस नहीं कर सकते।
  3. प्रदर्शन में गिरावट: आरटीटीआई का उपयोग वास्तव में अपवाद के प्रकार को खोजने के लिए किया जाता है जो अतिरिक्त ओवरहेड लगाता है। इस प्रकार अपवाद आमतौर पर होने वाले उपयोग के मामलों को संभालने के लिए उपयुक्त नहीं हैं (उपयोगकर्ता स्ट्रिंग आदि के बजाय इंट में प्रवेश करते हैं)।

2
1. लेकिन कुछ भाषाओं में अपवाद एक टोपी की एक बूंद पर फेंक दिए जाते हैं । 3. कभी-कभी प्रदर्शन से कोई फर्क नहीं पड़ता। (समय का 80%?)
चाचा नेव्स

2
2. सी ++ प्रोग्राम लगभग हमेशा अपवादों का उपयोग करते हैं, क्योंकि मानक पुस्तकालय का बहुत अधिक उपयोग करता है। कंटेनर कक्षाएं फेंक देते हैं। स्ट्रिंग क्लास फेंकता है। धारा कक्षाएं फेंक देते हैं।
डेविड थॉर्नले

सिवाय कंटेनर और स्ट्रिंग ऑपरेशन के क्या फेंकते हैं at()? कहा कि, कोई भी newफेंक सकता है, ...
पावेल मिनावे

जहाँ तक मेरी समझ में आरटीआई ट्राई / थ्रो / कैच के लिए कड़ाई से आवश्यक नहीं है। प्रदर्शन में गिरावट का हमेशा उल्लेख किया गया है, और मुझे विश्वास है, लेकिन कोई भी कभी किसी पैमाने या किसी संदर्भ के लिंक का उल्लेख नहीं करता है।
कैटस्कुल

अंकल बेंस: (1) मेंटेनेंस के लिए है न कि परफॉर्मेंस के लिए। प्रयास / पकड़ने / फेंकने के लिए अत्यधिक उपयोग कोड की पठनीयता को कम करता है। अंगूठे का नियम (और मैं इसके लिए आग में आ सकता हूं लेकिन इसकी सिर्फ मेरी राय है), प्रवेश और निकास बिंदुओं को कम, कोड को पढ़ने में जितना आसान होगा। डेविड थॉर्नले: जब आपको इंटरऑपरेबिलिटी की जरूरत न हो। जब आप C कोड से पुकारे जाने वाले पुस्तकालय को संकलित कर रहे हैं, तो gcc अपवादों में फ्लैग-अपवादों को अक्षम करता है।
श्रीधर अय्यर

2

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


2

एक बहुत ही व्यावहारिक कारण यह है कि जब मैं किसी प्रोग्राम को डिबगिंग करता हूं, तो अक्सर किसी एप्लिकेशन को डीबग करने के लिए फर्स्ट चांस एक्सेप्शन (डिबग -> एक्सेप्शन) पर फ्लिप करता हूं। यदि बहुत सारे अपवाद हो रहे हैं, तो यह खोजना बहुत मुश्किल है कि कुछ "गलत" कहां गया है।

इसके अलावा, यह कुख्यात "कैच थ्रो" जैसे कुछ विरोधी पैटर्न की ओर जाता है और वास्तविक समस्याओं को रोकता है। उस विषय पर अधिक जानकारी के लिए मैं इस विषय पर एक ब्लॉग पोस्ट देखें ।


2

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

इसके लिए काउंटर तर्क यह है कि आलसी लोगों को अपने पैरों में खुद को गोली मारने के लिए अधिक टाइप करने की आवश्यकता होती है।

Google की कोडिंग नीति यह कहती है कि अपवादों का उपयोग कभी न करें , विशेषकर C ++ में। आपका आवेदन या तो अपवादों को संभालने के लिए तैयार नहीं है या यह है। यदि ऐसा नहीं है, तो अपवाद शायद तब तक इसे प्रचारित करेगा जब तक कि आपके आवेदन की मृत्यु नहीं हो जाती।

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


1

अपवाद फेंकने के लिए वैध मामला:

  • आप एक फ़ाइल खोलने की कोशिश करते हैं, यह वहां नहीं है, एक FileNotFoundException को फेंक दिया गया है;

अवैध मामला:

  • आप केवल कुछ करना चाहते हैं यदि कोई फ़ाइल मौजूद नहीं है, तो आप फ़ाइल को खोलने का प्रयास करते हैं, और फिर कैच ब्लॉक में कुछ कोड जोड़ते हैं।

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

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

RecordIterator<MyObject> ri = createRecordIterator();
try {
   MyObject myobject = ri.next();
} catch(NoSuchElement exception) {
   // Object doesn't exist, will create it
}

यह बेहतर होगा:

RecordIterator<MyObject> ri = createRecordIterator();
if (ri.hasNext()) {
   // It exists! 
   MyObject myobject = ri.next();
} else {
   // Object doesn't exist, will create it
}

एंसर से जुड़ी टिप्पणी:

शायद मेरा उदाहरण बहुत अच्छा नहीं था - ri.next () को दूसरे उदाहरण में अपवाद नहीं फेंकना चाहिए, और यदि ऐसा होता है, तो वास्तव में कुछ असाधारण है और कुछ अन्य कार्रवाई कहीं और की जानी चाहिए। जब उदाहरण 1 का भारी उपयोग किया जाता है, तो डेवलपर्स विशिष्ट के बजाय एक सामान्य अपवाद को पकड़ लेंगे और मान लेंगे कि अपवाद उस त्रुटि के कारण है जिसकी वे अपेक्षा कर रहे हैं, लेकिन यह किसी और चीज़ के कारण हो सकता है। अंत में, यह वास्तविक अपवादों को नजरअंदाज करता है क्योंकि अपवाद अनुप्रयोग प्रवाह का हिस्सा बन गया है, और इसके अपवाद नहीं।

इस पर टिप्पणियाँ मेरे उत्तर से अधिक स्वयं को जोड़ सकती हैं।


1
क्यों नहीं? आप जिस 2 केस का उल्लेख करते हैं उसके अपवादों का उपयोग क्यों नहीं करते? पूछने वाला नियमों के कारणों को जानना चाहता है, नियमों को नहीं।
j_random_hacker

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

शायद मेरा उदाहरण बहुत अच्छा नहीं था - ri.next () को दूसरे उदाहरण में अपवाद नहीं फेंकना चाहिए, और यदि ऐसा होता है, तो वास्तव में कुछ असाधारण है और कुछ अन्य कार्रवाई कहीं और की जानी चाहिए। जब उदाहरण 1 का भारी उपयोग किया जाता है, तो डेवलपर्स विशिष्ट के बजाय एक सामान्य अपवाद को पकड़ लेंगे और मान लेंगे कि अपवाद उस त्रुटि के कारण है जिसकी वे अपेक्षा कर रहे हैं, लेकिन यह किसी और चीज़ के कारण हो सकता है। अंत में, यह वास्तविक अपवादों को नजरअंदाज करता है क्योंकि अपवाद अनुप्रयोग प्रवाह का हिस्सा बन गया है, और इसके अपवाद नहीं।
रवि वालेउ

तो आप कह रहे हैं: समय के साथ, अन्य बयान tryब्लॉक के अंदर जमा हो सकते हैं और फिर आप कुछ और नहीं हैं कि catchब्लॉक वास्तव में उस चीज को पकड़ रहा है जिसे आपने सोचा था कि यह पकड़ रहा है - क्या यह सही है? हालांकि अगर एक ही तरह से चीजों का एक सेट के बजाय एक बार में केवल 1 चीज का परीक्षण किया जा सकता है, तो एक ही तरीके से अगर / फिर / अन्यथा दृष्टिकोण का दुरुपयोग करना कठिन है, इसलिए अपवाद दृष्टिकोण अधिक नाजुक कोड हो सकता है। यदि ऐसा है तो कृपया अपने उत्तर में चर्चा करें और मैं खुशी से +1 करूंगा, क्योंकि मुझे लगता है कि कोड नाजुकता एक कारण है।
j_random_hacker 2

0

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

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


0

मुझे लगता है, "इसे शायद ही कभी उपयोग करें" यह सही वाक्य नहीं है। मैं "केवल असाधारण स्थितियों में फेंकना" पसंद करूंगा।

कई लोगों ने समझाया कि सामान्य परिस्थितियों में अपवादों का उपयोग क्यों नहीं किया जाना चाहिए। अपवादों को त्रुटि से निपटने और विशुद्ध रूप से त्रुटि से निपटने के लिए उनका अधिकार है।

मैं एक अन्य बिंदु पर ध्यान केंद्रित करूंगा:

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

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

तो आप बिना किसी जान-पहचान के अपने प्रोसेसर को जलाकर खत्म कर देंगे।

इसलिए: केवल असाधारण मामलों में अपवादों का उपयोग करें - अर्थ: जब वास्तविक त्रुटियां हुईं!


1
"इसका कारण यह है कि अपवाद न केवल बहुत शक्तिशाली गोट-स्टेटमेंट हैं, उन्हें उन सभी फ़्रेमों के लिए स्टैक को खोलना होगा जो इस प्रकार छोड़ते हैं। इस प्रकार स्टैक पर ऑब्जेक्ट्स को भी डिकंस्ट्रक्ट किया जाना है और इसी तरह।" - यदि आप कॉलस्टैक पर कई स्टैक फ्रेम नीचे कर रहे हैं, तो उन सभी स्टैक फ्रेम (और उन पर ऑब्जेक्ट्स) को अंततः वैसे भी नष्ट करना होगा - इससे कोई फर्क नहीं पड़ता कि ऐसा होता है क्योंकि आप सामान्य रूप से वापस आते हैं, या क्योंकि आप एक फेंक देते हैं अपवाद। अंत में, फोन करने की कमी std::terminate(), आपको अभी भी विनाश करना है।
पावेल मिनाएव

आप बिल्कुल सही हैं। लेकिन फिर भी कृपया याद रखें: हर बार जब आप अपवादों का उपयोग करते हैं, तो सिस्टम को यह सब जादुई तरीके से करने के लिए बुनियादी ढाँचा प्रदान करना होता है। मैं बस थोड़ा स्पष्ट करना चाहता था, कि यह केवल एक गोटो नहीं है। अनइंडिंग पर भी, सिस्टम को सही कैचिंग प्लेस ढूंढना होगा, अतिरिक्त समय, कोड और RTTI के उपयोग पर क्या खर्च होगा। तो यह एक छलांग की तुलना में बहुत अधिक है - ज्यादातर लोगों को यह समझ में नहीं आता है।
Juergen

जब तक आप मानक-अनुरूप C ++ से चिपके रहते हैं, RTTI अपरिहार्य है। अन्यथा, निश्चित रूप से ओवरहेड है। यह सिर्फ इतना है कि मैं अक्सर इसे अतिरंजित देखता हूं।
पावेल मिनाएव

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

आई। आई। इस सूत्र में जहाँ बहुत से कारणों का हवाला दिया गया है। बस उन्हें पढ़ो। मैं केवल एक का वर्णन करना चाहता था। अगर यह आपकी जरूरत नहीं है, तो मुझे दोष मत दीजिए।
Juergen

0

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

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

मेरा मानना ​​है कि एक अच्छी प्रोग्रामिंग भाषा अपवादों का समर्थन नहीं करती है क्योंकि हम उन्हें सी ++ और जावा में जानते हैं। आपको प्रोग्रामिंग भाषाओं का विकल्प चुनना चाहिए जो फ़ंक्शन से सभी प्रकार के रिटर्न मानों के लिए वैकल्पिक प्रवाह प्रदान कर सकें। प्रोग्रामर को एक रूटीन के आउटपुट के सभी रूपों की आशंका के लिए ज़िम्मेदार होना चाहिए और उन्हें एक अलग कोड फ़ाइल में संभालना चाहिए अगर मुझे अपना रास्ता मिल सकता है।


0

मैं अपवादों का उपयोग करता हूं यदि:

  • एक त्रुटि हुई जो स्थानीय और से बरामद नहीं की जा सकती है
  • यदि प्रोग्राम से त्रुटि बरामद नहीं हुई है, तो उसे समाप्त कर देना चाहिए।

यदि त्रुटि को पुनर्प्राप्त किया जा सकता है (उपयोगकर्ता ने एक संख्या के बजाय "सेब" में प्रवेश किया है) तो पुनर्प्राप्त करें (इनपुट के लिए फिर से पूछें, डिफ़ॉल्ट मान में परिवर्तन, आदि)।

यदि त्रुटि स्थानीय रूप से पुनर्प्राप्त नहीं की जा सकती है, लेकिन एप्लिकेशन जारी रह सकता है (उपयोगकर्ता ने एक फ़ाइल खोलने की कोशिश की लेकिन फ़ाइल मौजूद नहीं है) तो एक त्रुटि कोड उपयुक्त है।

यदि त्रुटि स्थानीय रूप से पुनर्प्राप्त नहीं की जा सकती है और एप्लिकेशन पुनर्प्राप्त किए बिना जारी नहीं रह सकता है (आप मेमोरी / डिस्क स्थान / आदि से बाहर हैं), तो एक अपवाद जाने का सही तरीका है।


1
-1। कृपया प्रश्न को ध्यान से पढ़ें। अधिकांश प्रोग्रामर या तो सोचते हैं कि अपवाद कुछ प्रकार की त्रुटि से निपटने के लिए उपयुक्त हैं, या वे कभी भी उपयुक्त नहीं हैं - वे प्रवाह नियंत्रण के अन्य, अधिक विदेशी रूपों के लिए उनका उपयोग करने की संभावना पर भी विचार नहीं करते हैं। सवाल यह है: ऐसा क्यों है?
j_random_hacker

आपको इसे ध्यान से पढ़ना भी चाहिए। मैंने उत्तर दिया कि "उनके उपयोग के साथ असाधारण रूढ़िवादी होने के पीछे दर्शन क्या है?" मेरे दर्शन के साथ रूढ़िवादी होने के साथ कि उनका उपयोग कैसे किया जाता है।
बिल

IMHO आपने यह नहीं बताया कि रूढ़िवाद क्यों आवश्यक है। वे कभी-कभी केवल "उपयुक्त" क्यों होते हैं? हर समय क्यों नहीं? Btw (मुझे लगता है कि अपने सुझाव दृष्टिकोण ठीक है, यह कम या ज्यादा क्या मैं अपने आप को, मैं सिर्फ नहीं इसका अधिकांश भाग पर हो जाता है लगता है कि है क्यों सवाल का।)
j_random_hacker

ओपी ने सात अलग-अलग सवाल पूछे। मैंने केवल एक उत्तर देना चुना। मुझे खेद है कि आप महसूस करते हैं कि यह एक डाउन वोट के लायक है।
बिल

0

किसने कहा कि उन्हें रूढ़िवादी रूप से इस्तेमाल किया जाना चाहिए? प्रवाह नियंत्रण के लिए अपवादों का कभी भी उपयोग न करें और इसे ही सही। और अपवाद की लागत की परवाह कौन करता है जब यह पहले से ही फेंक दिया जाता है?


0

मेरे दो सेंट:

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

मेरे लिए एक महान उदाहरण, फ़ाइल हैंडलिंग, या डेटाबेस हैंडलिंग है। मान लें कि सब कुछ ठीक है, और अंत में या कुछ अपवाद होने पर अपनी फ़ाइल बंद करें। या अपवाद होने पर अपने लेन-देन को रोलबैक करें।

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

जैसा कि पहले उल्लेख किया गया है, एक पारसेन्ट के लिए, मुझे अपवादों का विचार पसंद है। बस मान लौटाओ। यदि पैरामीटर पारगम्य नहीं था, तो एक अपवाद फेंक दें। यह एक ओर आपके कोड को क्लीनर बनाता है। कॉलिंग स्तर पर, आपको कुछ ऐसा करने की आवश्यकता है

try 
{
   b = ParseInt(some_read_string);
} 
catch (ParseIntException &e)
{
   // use some default value instead
   b = 0;
}

कोड साफ है। जब मुझे ParseInt मिलता है जैसे यह सब बिखरा हुआ है, तो मैं आवरण कार्य करता हूं जो अपवादों को संभालता है और मुझे डिफ़ॉल्ट मान लौटाता है। उदाहरण के लिए

int ParseIntWithDefault(String stringToConvert, int default_value=0)
{
   int result = default_value;
   try
   {
     result = ParseInt(stringToConvert);
   }
   catch (ParseIntException &e) {}

   return result;
}

इसलिए यह निष्कर्ष निकालने के लिए: मैंने जो चर्चा में चूक की, वह यह तथ्य था कि अपवाद मुझे अपने कोड को आसान / अधिक पठनीय बनाने की अनुमति देते हैं क्योंकि मैं त्रुटि स्थितियों को और अधिक अनदेखा कर सकता हूं। समस्या:

  • अपवादों को अभी भी संभालने की जरूरत है। अतिरिक्त समस्या: c ++ में सिंटैक्स नहीं है जो इसे निर्दिष्ट करने की अनुमति देता है कि कौन सा अपवाद फेंक सकता है (जैसे जावा करता है)। इसलिए कॉलिंग स्तर ज्ञात नहीं है कि किन अपवादों को संभालने की आवश्यकता हो सकती है।
  • कभी-कभी कोड बहुत वर्बोज़ प्राप्त कर सकता है, यदि प्रत्येक फ़ंक्शन को कोशिश / कैच ब्लॉक में लपेटने की आवश्यकता होती है। लेकिन कभी-कभी यह अभी भी समझ में आता है।

ताकि कभी-कभी एक अच्छा संतुलन खोजने में मुश्किल हो।


-1

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

बस प्रोग्रामिंग के हर नियम के बारे में वास्तव में एक दिशानिर्देश है, "यह मत करो" जब तक आपके पास वास्तव में अच्छा कारण नहीं है ":" कभी भी गोटो का उपयोग न करें "," वैश्विक चर से बचें "," नियमित अभिव्यक्तियाँ एक के बाद एक आपकी समस्याओं को बढ़ाती हैं। “, आदि अपवाद कोई अपवाद नहीं हैं…।


... और पूछने वाला जानना चाहेगा कि यह अंगूठे का नियम क्यों है, बजाय सुनने के (अभी तक) कि यह अंगूठे का नियम है। -1।
j_random_hacker

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

कोई निश्चित "क्यों" नहीं हो सकता है, लेकिन आंशिक रूप से "क्यों" दूसरों का उल्लेख है, उदाहरण के लिए "क्योंकि यह वही है जो हर कोई कर रहा है" (IMHO एक दुखद लेकिन वास्तविक कारण) या "प्रदर्शन" (IMHO इस कारण आमतौर पर ओवरस्टैट किया गया है , लेकिन यह एक कारण है)। गोमो से बचने जैसे अंगूठे के अन्य नियमों के बारे में भी यही सच है (आमतौर पर, यह एक समान लूप से अधिक नियंत्रण प्रवाह विश्लेषण को जटिल करता है) और वैश्विक चर से बचने (वे संभावित रूप से बहुत सारे युग्मन का परिचय देते हैं, जिससे बाद में कोड में बदलाव करना मुश्किल हो जाता है, और आमतौर पर समान होता है लक्ष्य कम युग्मन अन्य तरीकों से प्राप्त किए जा सकते हैं)।
j_random_hacker

और उन सभी कानाफूसी में कैवियट की लंबी सूची है जो मेरा जवाब था। प्रोग्रामिंग में व्यापक अनुभव से परे कोई वास्तविक नहीं है। अंगूठे के कुछ नियम हैं जो आगे बढ़ते हैं। अंगूठे का एक ही नियम "विशेषज्ञों" के कारण असहमत हो सकता है। आप स्वयं नमक के एक दाने के साथ "प्रदर्शन" करते हैं। यह मेरी सूची में सबसे ऊपर होगा। प्रवाह नियंत्रण विश्लेषण भी मेरे साथ पंजीकृत नहीं है क्योंकि (जैसे "कोई गोटो" नहीं) मुझे लगता है कि प्रवाह नियंत्रण मुद्दे अतिरंजित हैं। मैं यह भी बताऊंगा कि मेरा उत्तर समझाने की कोशिश करता है कि आप "ट्राइट" उत्तर का उपयोग कैसे करते हैं।
jmucchiello

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