सबसे पहले, के रूप में दूसरों ने कहा है, बातें नहीं कर रहे हैं कि सी में स्पष्ट कटौती ++, IMHO ज्यादातर क्योंकि आवश्यकताओं और मजबूरी कुछ और अधिक सी में विविध रहे हैं ++ अन्य भाषाओं की तुलना में, esp। सी # और जावा, जिसमें "समान" अपवाद मुद्दे हैं।
मैं std पर प्रकट करता हूँ :: stof उदाहरण:
std :: stof (अमान्य_argument फेंक देगा) के लिए एक रिक्त स्ट्रिंग पास करना एक प्रोग्रामिंग त्रुटि नहीं है
मूल अनुबंध , जैसा कि मैं इसे देखता हूं, इस फ़ंक्शन का यह है कि यह तर्क को फ्लोट में बदलने की कोशिश करता है, और ऐसा करने में किसी भी विफलता को अपवाद द्वारा सूचित किया जाता है। दोनों संभावित अपवादों को logic_error
प्रोग्रामर-त्रुटि के अर्थ में नहीं बल्कि "इनपुट नहीं, कभी, एक फ्लोट में परिवर्तित किया जा सकता है" के अर्थ से लिया गया है।
यहाँ, एक कह सकता है कि logic_error
यह इंगित करने के लिए उपयोग किया जाता है कि, (रनटाइम) इनपुट को देखते हुए, इसे बदलने की कोशिश करने के लिए हमेशा एक त्रुटि होती है - लेकिन यह निर्धारित करने और आपको बताने के लिए फ़ंक्शन का काम है (अपवाद के माध्यम से)।
साइड नोट: उस दृश्य में, एक चीज़ के रूप में देखा runtime_error
जा सकता है, जो किसी फ़ंक्शन को एक ही इनपुट देता है, सैद्धांतिक रूप से अलग-अलग रनों के लिए सफल हो सकता है। (जैसे एक फ़ाइल ऑपरेशन, DB पहुँच, आदि)
आगे की ओर ध्यान दें: C ++ रेगेक्स लाइब्रेरी ने इसे प्राप्त करने के लिए चुना , runtime_error
हालांकि इसमें ऐसे मामले हैं जहां इसे (अमान्य रेगेक्स पैटर्न) के रूप में वर्गीकृत किया जा सकता है।
यह सिर्फ दिखाता है, IMHO, कि या त्रुटि में समूहीकरण सी ++ में बहुत फजी हैlogic_
runtime_
और वास्तव में सामान्य मामले में ज्यादा मदद नहीं करता है (*) - यदि आपको विशिष्ट त्रुटियों को संभालने की आवश्यकता है, तो आपको संभवतः दोनों की तुलना में कम पकड़ने की आवश्यकता है।
(*): यह कहना है कि कोड के एक टुकड़े के अनुरूप नहीं होना चाहिए नहीं है, लेकिन है कि क्या आप फेंक runtime_
या logic_
या custom_
somethings वास्तव में है कि महत्वपूर्ण है, मुझे लगता है कि नहीं।
दोनों पर टिप्पणी करने के लिए stof
और bitset
:
दोनों कार्य तर्क के रूप में तार लेते हैं , और दोनों मामलों में यह है:
- कॉलर के लिए जाँचने के लिए गैर-तुच्छ कि क्या एक दी गई स्ट्रिंग वैध है (उदाहरण के लिए सबसे खराब स्थिति आपको फ़ंक्शन लॉजिक को दोहराना होगा; बिटसेट के मामले में, यह तुरंत स्पष्ट नहीं है कि क्या खाली स्ट्रिंग मान्य है, इसलिए ctor तय करें)
- यह स्ट्रिंग को "पार्स" करने के लिए फ़ंक्शन की जिम्मेदारी पहले से ही है, इसलिए इसे पहले से ही स्ट्रिंग को मान्य करना है, इसलिए यह समझ में आता है कि यह स्ट्रिंग को समान रूप से "उपयोग" करने के लिए एक त्रुटि की रिपोर्ट करता है (और दोनों मामलों में यह एक अपवाद है) ।
नियम जो अपवादों के साथ अक्सर आता है, "असाधारण परिस्थितियों में केवल अपवादों का उपयोग करें"। लेकिन एक लाइब्रेरी फ़ंक्शन को कैसे पता होना चाहिए कि कौन सी परिस्थितियां असाधारण हैं?
यह कथन, IMHO, दो जड़ें हैं:
प्रदर्शन : यदि किसी फ़ंक्शन को एक महत्वपूर्ण पथ में बुलाया जाता है, और "असाधारण" मामला असाधारण नहीं है, अर्थात पास की एक महत्वपूर्ण राशि में अपवाद फेंकना शामिल होगा, तो अपवाद-अनइंडिंग-मशीनरी के लिए हर बार भुगतान करने का कोई मतलब नहीं है , और बहुत धीमा हो सकता है।
एरर हैंडलिंग की स्थानीयता : यदि किसी फ़ंक्शन को इनवॉइस किया जाता है और अपवाद तुरंत पकड़ा और संसाधित किया जाता है, तो एक अपवाद को फेंकने में बहुत कम बिंदु है, क्योंकि त्रुटि हैंडलिंग ए के साथ की catch
तुलना में अधिक क्रिया होगी if
।
उदाहरण:
float readOrDefault;
try {
readOrDefault = stof(...);
} catch(std::exception&) {
// discard execption, just use default value
readOrDefault = 3.14f; // 3.14 is the default value if cannot be read
}
यहां ऐसे कार्य किए गए हैं जैसे TryParse
बनाम Parse
खेलने में आते हैं: जब स्थानीय कोड के लिए एक संस्करण पार्स स्ट्रिंग को मान्य होने की उम्मीद करता है, तो एक संस्करण जब स्थानीय कोड मानता है कि यह वास्तव में अपेक्षित है (यानी गैर असाधारण) जो पार्सिंग विफल हो जाएगा।
वास्तव में, stof
बस (एक के रूप में परिभाषित) चारों ओर एक आवरण strtof
, इसलिए यदि आप अपवाद नहीं चाहते हैं, तो उस एक का उपयोग करें।
इसलिए, मुझे यह कैसे तय करना चाहिए कि मुझे किसी विशेष कार्य के लिए अपवादों का उपयोग करना चाहिए या नहीं?
IMHO, आपके पास दो मामले हैं:
फ़ंक्शन की तरह "लाइब्रेरी" (विभिन्न संदर्भों में अक्सर उपयोग किया जाता है): आप मूल रूप से तय नहीं कर सकते। संभवतः दोनों संस्करण प्रदान करते हैं, हो सकता है कि एक त्रुटि की रिपोर्ट करता है और एक आवरण जो एक अपवाद में लौटे त्रुटि को परिवर्तित करता है।
"एप्लिकेशन" फ़ंक्शन (एप्लिकेशन कोड की एक बूँद के लिए विशिष्ट, कुछ का पुन: उपयोग किया जा सकता है, लेकिन ऐप्स त्रुटि शैली से निपटने के लिए विवश है, आदि): यहां, यह अक्सर बहुत स्पष्ट कटौती होनी चाहिए। यदि कोड पथ (फ़ंक्शंस) कॉलिंग फ़ंक्शन अपवादों को एक समझदार और उपयोगी तरीके से हैंडल करता है, तो अपवादों का उपयोग किसी भी रिपोर्ट करने के लिए करें (लेकिन नीचे देखें) त्रुटि। यदि एप्लिकेशन कोड अधिक आसानी से एक त्रुटि वापसी शैली के लिए पढ़ा और लिखा जाता है, तो हर तरह से उपयोग करें।
बेशक वहाँ बीच में जगह होगी - बस का उपयोग करें क्या जरूरत है और याद रखें YAGNI।
अंतिम, मुझे लगता है कि मुझे अक्सर पूछे जाने वाले प्रश्न पर वापस जाना चाहिए,
किसी फ़ंक्शन के उपयोग में कोडिंग त्रुटि को इंगित करने के लिए थ्रो का उपयोग न करें। इस प्रक्रिया को डिबगर में भेजने के लिए या प्रक्रिया को क्रैश करने के लिए अभिकारक या अन्य तंत्र का उपयोग करें ...
मैं उन सभी त्रुटियों के लिए सदस्यता लेता हूं जो स्पष्ट संकेत हैं कि कुछ गंभीर रूप से गड़बड़ है या कि कॉलिंग कोड स्पष्ट रूप से नहीं जानता कि यह क्या कर रहा था।
लेकिन जब यह उपयुक्त होता है तो अक्सर अत्यधिक विशिष्ट होता है, इसलिए लाइब्रेरी डोमेन बनाम एप्लिकेशन डोमेन के ऊपर देखें।
यह इस सवाल पर वापस आता है कि कॉलिंग पूर्व शर्त को कैसे और कैसे मान्य किया जाए , लेकिन मैं इसमें नहीं जाऊंगा, उत्तर पहले से ही बहुत लंबा है :)