अभिकथन या अपवाद का उपयोग करके अनुबंध द्वारा डिजाइन? [बन्द है]


123

जब कोई फ़ंक्शन या विधि अनुबंध द्वारा प्रोग्रामिंग करता है, तो पहले यह जांचता है कि क्या इसकी जिम्मेदारियों को पूरा करने से पहले, इसकी जिम्मेदारियों को पूरा करने के लिए, सही है? इन जांचों को करने के दो सबसे प्रमुख तरीके हैं- बाय assertऔर बाय exception

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

आपके हिसाब से कौन सा बेहतर है?

Releated प्रश्न देखें यहां


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

अच्छा सवाल है, लेकिन मुझे लगता है कि आपको वास्तव में स्वीकृत उत्तर को स्विच करना चाहिए (जैसा कि वोट दिखाते हैं, भी)!
डेवफर

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

इस प्रतिक्रिया में बहुत ही विनम्र प्रतिक्रिया दी गई है : "दूसरे शब्दों में, अपवाद आपके आवेदन की मजबूती को संबोधित करते हैं जबकि दावे इसकी शुद्धता को दर्शाते हैं।"
शमूएल लेविन

जवाबों:


39

रिलीज़ बिल्ड में मुखरता अक्षम करना यह कहने जैसा है कि "मेरे पास रिलीज़ बिल्ड में कभी भी कोई समस्या नहीं होगी", जो अक्सर ऐसा नहीं होता है। इसलिए मुखर को रिलीज बिल्ड में अक्षम नहीं होना चाहिए। लेकिन आप नहीं चाहते हैं कि जब भी या तो त्रुटियां हों, तो रिलीज रिलीज दुर्घटनाग्रस्त हो जाए?

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


4
उन मामलों में बहुत कम उपयोगी होते हैं, जहां सही तरीके से लागू करने के लिए जाँच करना या तो अक्षम या अक्षम होगा।
केसबश

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

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

5
@jalf, यद्यपि आप रिलीज़ बिल्ड में अपने डिबगर में हुक नहीं लगा सकते हैं, आप लॉगिंग का लाभ उठा सकते हैं, ताकि डेवलपर्स को आपके दावे के लिए प्रासंगिक जानकारी दिखाई दे। इस दस्तावेज़ ( martinfowler.com/ieeeSoftware/failFast.pdf ) में, जिम शोर बताते हैं, "याद रखें, ग्राहक की साइट पर होने वाली एक त्रुटि ने इसे आपकी परीक्षण प्रक्रिया के माध्यम से बनाया है। आपको शायद इसे पुन: प्रस्तुत करने में परेशानी होगी। ये त्रुटियां हैं।" खोजने के लिए सबसे कठिन है, और समस्या को समझाने वाला एक सुव्यवस्थित जोर आपको प्रयास के दिनों को बचा सकता है। "
स्ट्रिपिंगवर्यर

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

194

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


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

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

यदि आपके फ़ंक्शन f (int * x) में एक लाइन x-> लेन है, तो f (v) जहां v शून्य साबित होता है, क्रैश की गारंटी है। इसके अलावा, अगर पहले भी v पर शून्य साबित होता है, तो f (v) कहा जाता है, तो आपके पास एक तार्किक विरोधाभास है। यह उसी तरह है जैसे a / b जहाँ b अंततः साबित होता है 0. आदर्श रूप से, ऐसा कोड संकलित करने में विफल होना चाहिए। जब तक मुद्दा चेक की लागत नहीं है, तब तक धारणा चेक को बंद करना पूरी तरह से मूर्खता है, क्योंकि यह उस स्थान को अस्पष्ट करता है जहां एक धारणा का उल्लंघन किया गया था। यह कम से कम लॉग इन होना चाहिए। आपके पास वैसे भी फिर से क्रैश डिज़ाइन होना चाहिए।
रॉब

22

मैं जिस सिद्धांत का पालन करता हूं वह यह है: यदि किसी स्थिति को कोडिंग से वास्तविक रूप से टाला जा सकता है तो एक जोर का प्रयोग करें। अन्यथा एक अपवाद का उपयोग करें।

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

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

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


6

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

इसी तरह परिणामों के बारे में सोचो। एक मुखर आमतौर पर एप्लिकेशन को बंद कर देता है। यदि कोई वास्तविक उम्मीद है कि हालत से उबर सकते हैं, तो आपको शायद एक अपवाद का उपयोग करना चाहिए।

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


5

यह बिल्कुल सच नहीं है कि "अभिकर्ता केवल डिबग मोड में विफल रहता है।"

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

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

क्या आपको हमेशा पूर्वधारणा जाँच सक्षम छोड़ देनी चाहिए? निर्भर करता है। यह आप पर निर्भर करता है। कोई सार्वभौमिक जवाब नहीं है। यदि आप बैंक के लिए सॉफ़्टवेयर बना रहे हैं, तो बेहतर हो सकता है कि 1,000 डॉलर के बदले $ 1,000,000 को स्थानांतरित करने के लिए खतरनाक संदेश के साथ निष्पादन को बाधित करें। लेकिन क्या होगा अगर आप एक गेम की प्रोग्रामिंग कर रहे हैं? हो सकता है कि आपको वह सभी गति चाहिए जो आपको मिल सकती है, और अगर किसी को बग के कारण 10 के बजाय 1000 अंक मिलते हैं, तो प्रीन्डॉन्डिशन को पकड़ नहीं पाया (क्योंकि वे सक्षम नहीं हैं), कठिन भाग्य।

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

संक्षेप में, आपके पास दावे हो सकते हैं और फिर भी अपवाद स्वतः प्राप्त हो सकते हैं , यदि आप उन्हें सक्षम करते हैं - कम से कम एफिल में। मुझे लगता है कि सी ++ में भी ऐसा ही करने की जरूरत है।

यह भी देखें: अभिकथन को उत्पादन कोड में कब रहना चाहिए?


1
आपकी बात निश्चित रूप से मान्य है। अतः किसी विशेष भाषा निर्दिष्ट नहीं किया है - सी # के मामले में मानक ज़ोर System.Diagnostics.Debug.Assert है, जो करता है केवल एक डीबग बिल्ड में असफल हो, और एक रिलीज के निर्माण में संकलन समय पर निकाल दिया जाएगा।
योयो

2

रिलीज़ बिल्ड में comp.lang.c ++ पर जोर देने में सक्षम / अक्षम करने के बारे में एक बड़ा धागा था । मॉडरेट किया गया था, जो कि अगर आपके पास कुछ हफ़्ते हैं तो आप देख सकते हैं कि इस पर राय कितनी भिन्न है। :)

कप्रो के विपरीत , मेरा मानना ​​है कि यदि आप सुनिश्चित नहीं हैं कि एक रिलीज बिल्ड में एक दावे को निष्क्रिय किया जा सकता है, तो यह एक मुखर नहीं होना चाहिए था। कार्यक्रम के आक्रमणकारियों के टूटने से बचाव करना है। ऐसे मामले में, जहाँ तक आपके कोड के ग्राहक का संबंध है, दो संभावित परिणामों में से एक होगा:

  1. ओएस के कुछ प्रकार की विफलता के साथ मरें, जिसके परिणामस्वरूप गर्भपात हो सकता है। (बिना मुखर)
  2. गर्भपात के लिए एक सीधी कॉल के माध्यम से मरो। (मुखर)

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

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

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


2

मैंने इस मामले की स्थिति पर अपना दृष्टिकोण रेखांकित किया: आप किसी वस्तु की आंतरिक स्थिति को कैसे मान्य करते हैं? । आम तौर पर, अपने दावों का दावा करते हैं और दूसरों द्वारा उल्लंघन के लिए फेंकते हैं। रिलीज बिल्ड में जोर डालने के लिए, आप कर सकते हैं:

  • महंगी जाँच के लिए दावा करना
  • तुच्छ चेक को सक्षम रखें (जैसे अशक्त सूचक या बूलियन मान के लिए जाँच)

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


1

आप डिज़ाइन-टाइम और रन-टाइम त्रुटियों के बीच अंतर के बारे में पूछ रहे हैं।

मुखर हैं 'अरे प्रोग्रामर, यह टूट गया है' सूचनाएँ, वे तुम्हें याद दिलाने के लिए वहाँ कीड़े की याद दिलाने के लिए हैं।

अपवाद 'हे उपयोगकर्ता, somethings गलत हो गए' सूचनाएँ (जाहिर है आप उन्हें पकड़ने के लिए कोड कर सकते हैं ताकि उपयोगकर्ता को कभी नहीं बताया जाए) लेकिन ये रन समय पर होने के लिए डिज़ाइन किए गए हैं जब जो उपयोगकर्ता ऐप का उपयोग कर रहा है।

इसलिए, यदि आपको लगता है कि आप अपने सभी बग्स को निकाल सकते हैं, केवल अपवादों का उपयोग करें। अगर आपको लगता है कि आप ..... अपवादों का उपयोग नहीं कर सकते। आप निश्चित रूप से अपवादों की संख्या को कम करने के लिए डिबग एसेट्स का उपयोग कर सकते हैं।

यह मत भूलो कि कई पूर्व शर्त उपयोगकर्ता द्वारा आपूर्ति किए गए डेटा होंगे, इसलिए आपको उपयोगकर्ता को सूचित करने के एक अच्छे तरीके की आवश्यकता होगी जो उसका डेटा अच्छा नहीं था। ऐसा करने के लिए, आपको अक्सर कॉल डेटा को बिट्स स्टैक से वापस करने की आवश्यकता होगी, जिसके साथ वह इंटर कर रहा है। जब आपका ऐप n-tier हो तो Asserts उपयोगी नहीं होगा।

अंत में, मैं न तो उपयोग करूँगा - त्रुटि कोड आपके द्वारा नियमित रूप से होने वाली त्रुटियों के लिए बहुत बेहतर हैं। :)


0

मैं दूसरे को पसंद करता हूं। जबकि आपके परीक्षण ठीक चल सकते हैं, मर्फी का कहना है कि कुछ अप्रत्याशित गलत हो जाएगा। इसलिए, वास्तविक त्रुटिपूर्ण विधि कॉल पर एक अपवाद प्राप्त करने के बजाय, आप एक NullPointerException (या समतुल्य) 10 स्टैक फ़्रेम को गहराई से ट्रेस करना समाप्त करते हैं।


0

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

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


0

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

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

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

#ifdef DEBUG
#define RETURN_IF_FAIL(expr)      do {                      \
 if (!(expr))                                           \
 {                                                      \
     fprintf(stderr,                                        \
        "file %s: line %d (%s): precondition `%s' failed.", \
        __FILE__,                                           \
        __LINE__,                                           \
        __PRETTY_FUNCTION__,                                \
        #expr);                                             \
     ::print_stack_trace(2);                                \
     return;                                                \
 };               } while(0)
#define RETURN_VAL_IF_FAIL(expr, val)  do {                         \
 if (!(expr))                                                   \
 {                                                              \
    fprintf(stderr,                                             \
        "file %s: line %d (%s): precondition `%s' failed.",     \
        __FILE__,                                               \
        __LINE__,                                               \
        __PRETTY_FUNCTION__,                                    \
        #expr);                                                 \
     ::print_stack_trace(2);                                    \
     return val;                                                \
 };               } while(0)
#else
#define RETURN_IF_FAIL(expr)
#define RETURN_VAL_IF_FAIL(expr, val)
#endif

अगर मुझे तर्क-वितर्क की जाँच की आवश्यकता है, तो मैं यह करूँगा:

char *doSomething(char *ptr)
{
    RETURN_VAL_IF_FAIL(ptr != NULL, NULL);  // same as assert(ptr != NULL), but returns NULL if it fails.
                                            // Goes away when debug off.

    if( ptr != NULL )
    {
       ...
    }

    return ptr;
}

मुझे नहीं लगता कि मैंने ओपी प्रश्न में सी ++ से संबंधित कुछ भी देखा है। मेरा मानना ​​है कि इसे आपके उत्तर में शामिल नहीं किया जाना चाहिए।
ForceMagic

@ForceMagic: प्रश्न का सी ++ टैग 2008 में था जब मैंने यह उत्तर पोस्ट किया था, और वास्तव में सी ++ टैग केवल 5 घंटे पहले हटा दिया गया था। बावजूद, कोड एक भाषा-स्वतंत्र अवधारणा को दिखाता है।
Indiv

0

मैंने अपने स्वयं के विचारों के साथ यहां कई अन्य उत्तरों को संश्लेषित करने की कोशिश की।

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

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

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


0

मेरे लिए, अंगूठे का नियम, बाहरी त्रुटियों के लिए आंतरिक त्रुटियों और अपवादों को खोजने के लिए मुखर अभिव्यक्तियों का उपयोग करना है। आप यहाँ से ग्रेग द्वारा निम्नलिखित चर्चा से बहुत लाभ उठा सकते हैं

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

यह समझने के लिए कि किसी कार्यक्रम में दावे कैसे फिट होते हैं, सी ++ प्रोग्राम में एक रूटीन पर विचार करें जो एक पॉइंटर को रोकना है। अब रूटीन परीक्षण करना चाहिए कि क्या सूचक डेरेफ़रिंग से पहले NULL है, या क्या यह दावा करना चाहिए कि पॉइंटर NULL नहीं है और फिर आगे जाएं और इसकी परवाह किए बिना इसे डिरेल करें?

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

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

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

पुनश्च: आप इसी तरह के प्रश्न की जाँच कर सकते हैं: अपवाद बनाम अभिकथन


-1

यह प्रश्न भी देखें :

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

इनपुट मानों को "सही" करने में समस्या यह है कि कॉलर को वह नहीं मिलेगा जो वे अपेक्षा करते हैं, और इससे समस्याएँ हो सकती हैं या कार्यक्रम के विभिन्न हिस्सों में दुर्घटनाग्रस्त हो सकती हैं, जिससे एक बुरा सपना हो सकता है।

यदि वे अक्षम होते हैं, तो मैं आमतौर पर अगर-बयान की भूमिका को संभालने के लिए एक अपवाद फेंक देता हूं

assert(value>0);
if(value<=0) throw new ArgumentOutOfRangeException("value");
//do stuff
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.