एक std से प्राप्त करना चाहिए / विरासत :: अपवाद?


15

अपनी पहली 'गंभीर' सी ++ लाइब्रेरी डिजाइन करते समय, मैं खुद से पूछ रहा हूं:

क्या यह अच्छी शैली है कि इससे अपवादों को प्राप्त करें std::exceptionऔर यह संतान है ?!

पढ़ने के बाद भी

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

और उदाहरण के लिए, मेरे उपयोगकर्ता दोषपूर्ण तर्कों की आपूर्ति करते हैं, जो एक फेंकने की तुलना में अधिक सुविधाजनक std::invalid_argumentहोगा, यह नहीं होगा? इसलिए std के सामान्य उपयोग के साथ संयुक्त :: अपवाद मैं दूसरों के कोड में देखता हूं: अपने कस्टम अपवाद वर्ग (जैसे lib_foo_exception) से और भी अधिक क्यों न हो std::exception

विचार?


मुझे यकीन नहीं है कि मैं फॉलो करता हूं। सिर्फ इसलिए कि आप विरासत में std::exceptionहैं इसका मतलब यह नहीं है कि आप एक फेंक देते हैंstd::exception । इसके अलावा, पहली जगह std::runtime_errorसे विरासत में मिला std::exceptionहै, और what()विधि से आता है std::exception, नहीं std::runtime_error। और आपको निश्चित रूप से जेनेरिक अपवादों को फेंकने के बजाय अपनी खुद की अपवाद कक्षाएं बनानी चाहिए std::runtime_error
विन्सेन्ट सेवार्ड

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

3
@LightnessRacesinOrbit मेरा मतलब है ... "के अलावा", "पकड़ने के लिए कितने तरीके हैं lib_foo_exception?" std::exceptionआप से विरासत में catch(std::exception)या के द्वारा यह कर सकते हैं catch(lib_foo_exception)। से व्युत्पन्न के बिना std::exception, आप इसे पकड़ लेंगे यदि और केवल यदि , द्वारा catch(lib_foo_exception)
सुपरलोककस

2
@Superlokkus: हम अनदेखी करते हैं catch(...)। यह इसलिए है क्योंकि भाषा उस मामले के लिए अनुमति देती है जिस पर आप विचार कर रहे हैं (और "दुर्व्यवहार" पुस्तकालयों के लिए), लेकिन यह आधुनिक सर्वोत्तम अभ्यास नहीं है।
मोनिका

1
C ++ में अपवाद-हैंडलिंग का बहुत सारा डिज़ाइन मोटे, अधिक सामान्य catchसाइटों को प्रोत्साहित करता है, और इसी तरह मोटे लेन-देन को भी करता है जो एक उपयोगकर्ता-अंत ऑपरेशन को मॉडल करता है। यदि आप इसकी तुलना उन भाषाओं से करते हैं जो सामान्यीकृत पकड़ने के विचार को बढ़ावा नहीं देते हैं std::exception&, उदाहरण के लिए, उनके पास अक्सर try/catchबहुत विशिष्ट त्रुटियों से संबंधित मध्यस्थ ब्लॉकों के साथ एक बहुत अधिक कोड होता है , जो अपवाद-हैंडलिंग की व्यापकता को कम कर देता है क्योंकि यह शुरू हो रहा है। मैनुअल एरर हैंडलिंग पर अधिक मजबूत जोर, और संभवतः सभी संभावित त्रुटियों पर भी।

जवाबों:


29

सभी अपवादों से विरासत में मिलना चाहिए std::exception

मान लीजिए, उदाहरण के लिए, मुझे कॉल करने की आवश्यकता है ComplexOperationThatCouldFailABunchOfWays(), और मैं किसी भी अपवाद को संभालना चाहता हूं जिसे वह फेंक सकता है। अगर सब कुछ विरासत में मिला है std::exception, तो यह आसान है। मुझे केवल एक catchब्लॉक की आवश्यकता है , और मेरे पास what()विवरण प्राप्त करने के लिए एक मानक इंटरफ़ेस ( ) है।

try {
    ComplexOperationThatCouldFailABunchOfWays();
} catch (std::exception& e) {
    cerr << e.what() << endl;
}

यदि अपवाद से विरासत में नहीं मिलता है std::exception, तो यह बहुत बदसूरत हो जाता है:

try {
    ComplexOperationThatCouldFailABunchOfWays();
} catch (std::exception& e) {
    cerr << e.what() << endl;
} catch (Exception& e) {
    cerr << e.Message << endl;
} catch (framework_exception& e) {
    cerr << e.Details() << endl;
}

फेंकने के लिए runtime_errorया invalid_argumentअपने स्वयं के std::exceptionउपवर्गों को बनाने या बनाने के बारे में : मेरे अंगूठे का नियम एक नई उपवर्ग का परिचय देना है जब भी मुझे किसी विशेष प्रकार की त्रुटि को अन्य त्रुटियों की तुलना में अलग करने की आवश्यकता होती है (यानी, जब भी मुझे एक अलग catchब्लॉक की आवश्यकता होती है )।

  • अगर मैं हर कल्पनीय प्रकार की त्रुटि के लिए एक नया अपवाद उपवर्ग का परिचय देता हूं, भले ही मुझे उन्हें अलग से संभालने की आवश्यकता न हो, तो यह बहुत सारे वर्ग प्रसार को जोड़ता है।
  • यदि मैं मौजूदा उपवर्गों का कुछ विशिष्ट उपयोग करने के लिए पुन: उपयोग करता हूं (अर्थात, यदि यहांruntime_error फेंका गया का अर्थ किसी सामान्य रनटाइम त्रुटि से अलग है), तो मैं मौजूदा उपवर्ग के अन्य उपयोगों के साथ संघर्ष का जोखिम उठाता हूं।
  • यदि मुझे विशेष रूप से एक त्रुटि को संभालने की आवश्यकता नहीं है, और यदि मैं जिस त्रुटि को फेंक रहा हूं, वह मौजूदा मानक लाइब्रेरी की त्रुटियों (जैसे invalid_argument) से बिल्कुल मेल खाती है , तो मैं मौजूदा कक्षा का पुन: उपयोग करता हूं। मुझे इस मामले में एक नया वर्ग जोड़ने का ज्यादा फायदा नहीं है। (C ++ कोर दिशानिर्देश मेरे यहाँ से असहमत हैं - वे हमेशा आपकी अपनी कक्षाओं का उपयोग करने की सलाह देते हैं।)

सी ++ कोर दिशानिर्देश आगे की चर्चा और उदाहरण है।


उन सभी ampersands! C ++ अजीब है।
सुपरजेडी २२४

2
@ SuperJedi224 और उन सभी विभिन्न पत्रों को! अंग्रेजी अजीब है।
जोहान्स

यह तर्क मेरे लिए मायने नहीं रखता है। क्या यह catch (...)(शाब्दिक दीर्घवृत्त के साथ) नहीं है?
मैक्सएम

1
@Maxpm catch (...)केवल तभी उपयोगी है जब आपको कुछ भी फेंकने की आवश्यकता नहीं है । यदि आप कुछ करना चाहते हैं - उदाहरण के लिए, उदाहरण के लिए, विशिष्ट त्रुटि संदेश दिखाएं या लॉग करें - तो आपको यह जानना होगा कि यह क्या है।
जोश केली

9

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

यह एक गलत धारणा है।

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

हां, अंत में सब कुछ विरासत में मिला std::exception। अक्सर, कि से विरासत में शामिल करेंगे std::runtime_errorया std::logic_error। आपके द्वारा लागू किए जा रहे अपवाद के वर्ग के लिए जो कुछ भी उपयुक्त है।

यह निश्चित रूप से व्यक्तिपरक है - कई लोकप्रिय पुस्तकालय पूरी तरह से मानक अपवाद प्रकारों की उपेक्षा करते हैं, संभवतः पुस्तकालयों को मानक पुस्तकालय से अलग करने के लिए। व्यक्तिगत रूप से मुझे लगता है कि यह बेहद स्वार्थी है! यह अपवादों को पकड़ता है जो सही होने के लिए बहुत अधिक कठिन हैं।

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

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.