2009-08-26 14 views
41

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

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

एक साथ काम करने के लिए 1 और 4 प्राप्त करना मेरे पास सबसे बड़ा मुद्दा है, क्योंकि किसी भी स्वरूपण और फ़ाइल आउटपुट विधियां संभावित रूप से विफल हो सकती हैं।

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

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

class Exception : public std::exception 
{ 
public: 
    //enum for each exception type, which can also be used to determin 
    //exception class, useful for logging or other localisation methods 
    //for generating a message of some sort. 
    enum ExceptionType 
    { 
     //shouldnt ever be thrown 
     UNKNOWN_EXCEPTION = 0, 
     //same as above but has a string that may provide some info 
     UNKNOWN_EXCEPTION_STR, 
     //eg file not found 
     FILE_OPEN_ERROR, 
     //lexical cast type error 
     TYPE_PARSE_ERROR, 
     //NOTE: in many cases functions only check and throw this in debug 
     INVALID_ARG, 
     //an error occured while trying to parse data from a file 
     FILE_PARSE_ERROR, 
    } 
    virtual ExceptionType getExceptionType()const throw() 
    { 
     return UNKNOWN_EXCEPTION; 
    } 
    virtual const char* what()throw(){return "UNKNOWN_EXCEPTION";} 
}; 
class FileOpenError : public Exception 
{ 
public: 
    enum Reason 
    { 
     FILE_NOT_FOUND, 
     LOCKED, 
     DOES_NOT_EXIST, 
     ACCESS_DENIED 
    }; 
    FileOpenError(Reason reason, const char *file, const char *dir)throw(); 
    Reason getReason()const throw(); 
    const char* getFile()const throw(); 
    const char* getDir()const throw(); 
private: 
    Reason reason; 
    static const unsigned FILE_LEN = 256; 
    static const unsigned DIR_LEN = 256; 
    char file[FILE_LEN], dir[DIR_LEN]; 
}; 

प्वाइंट 1 संबोधित किया जाता है (यदि आवश्यक छोटा है, लेकिन हमेशा समाप्त नल)।

हालांकि यह बिंदु 3 को संबोधित नहीं करता है, हालांकि मुझे लगता है कि वास्तविक दुनिया में वास्तविक बिंदु में सीमित उपयोग की संभावना है, और यदि आवश्यक हो तो एक नया अपवाद फेंकने की संभावना अधिक हो सकती है।

उत्तर

2

एक अच्छा डिज़ाइन अपवाद वर्गों का सेट नहीं बनाना है - केवल std :: अपवाद के आधार पर प्रति लाइब्रेरी बनाएं।

जानकारी जोड़ना काफी आसान है:

try { 
    ... 
} 
catch(const MyEx & ex) { 
    throw MyEx(ex.what() + " more local info here"); 
} 

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

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

इससे पहले पूछा गया है, मुझे लगता है, लेकिन मुझे अभी यह नहीं मिल रहा है।

+1

यह एक? http://stackoverflow.com/questions/1157591/c-exception-handing – GManNickG

+0

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

+8

विभिन्न कक्षाओं के साथ क्या गलत है? आप उन्हें अलग-अलग संभालना चाहते हैं, या यहां तक ​​कि कुछ को संभालना और दूसरों को छोड़ना चाहते हैं। –

7

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

boost site

+1

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

+0

क्या यह अकल्पनीय है कि एक अपवाद एक से अधिक प्रकार की समस्या के कारण हो सकता है? –

+5

कोई स्पष्ट रूप से अनुप्रयोग लिखता है और पुस्तकालय नहीं। संरचना कानूनी सी ++ है और इस तरह इस तथ्य के बावजूद इसका उपयोग किया जाएगा कि कोई भी "अपवाद वर्गों के लिए इसका उपयोग करने के किसी भी कारण को नहीं देखता"। यदि आप क्षमा चाहते हैं तो जॉन को अपवर्तित करना होगा - pgast 0 secs ago – pgast

7


2 पर अन्य समान रूप से उपयोगी सलाह: नहीं आप यूजर इंटरफेस (= स्थानीय संदेशों) कार्यक्रम तर्क के साथ मिश्रित नहीं करना चाहिए। उपयोगकर्ता को संचार बाहरी स्तर पर किया जाना चाहिए जब आवेदन यह महसूस करता है कि यह समस्या को संभाल नहीं सकता है। अपवाद में अधिकांश जानकारी किसी भी उपयोगकर्ता को दिखाने के लिए कार्यान्वयन विवरण का बहुत अधिक है।
3: इस
5 के लिए boost.exception का उपयोग करें 5: ऐसा न करें। देखें 2. लॉग करने का निर्णय हमेशा त्रुटि प्रबंधन साइट पर होना चाहिए।

केवल एक प्रकार का अपवाद उपयोग न करें। पर्याप्त प्रकार का उपयोग करें ताकि एप्लिकेशन प्रत्येक प्रकार की त्रुटि वसूली के लिए एक अलग पकड़ हैंडलर का उपयोग कर सके

23

अपवाद कक्षाओं के उथले पदानुक्रम का उपयोग करें। पदानुक्रम को बहुत गहरा बनाना मूल्य की तुलना में अधिक जटिलता जोड़ता है।

std :: अपवाद (या std :: runtime_error जैसे अन्य मानक अपवादों में से एक) से अपवाद कक्षाएं प्राप्त करें। यह आपके द्वारा किए गए अपवादों से निपटने के लिए शीर्ष स्तर पर जेनेरिक अपवाद हैंडलर की अनुमति देता है। उदाहरण के लिए, एक अपवाद हैंडलर हो सकता है जो त्रुटियों को लॉग करता है।

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

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

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

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

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

+1

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

+5

अपवाद को संभालने वाला कैच ब्लॉक संसाधनों से यूआई स्ट्रिंग को लोड करना चाहिए। कुछ ऐसा: 'पकड़ (कॉन्स सिंटैक्स_एर और पूर्व) {std :: cerr << ex.filename() << "(" << ex.line_number() << "):" << GetText (IDS_SYNTAXERROR) << std: : endl; } ', जहां' GetText() 'आपके प्रोग्राम के संसाधनों से एक स्ट्रिंग लोड करता है। –

+0

सी ++ 11 या सी ++ 17 आपके उत्तर में कुछ भी बदल देगा? हालांकि मुझे सी ++ 17 की तुलना में सी ++ 11 में अधिक दिलचस्पी है। – Gizmo

4

सीधे एक अपवाद वर्ग पदानुक्रम के डिजाइन से संबंधित नहीं है, लेकिन महत्वपूर्ण है (और उनमें से किसी अपवाद का उपयोग कर से संबंधित) है कि आप करना चाहिए आम तौर पर throw by value and catch by reference.

इस फेंका अपवाद की स्मृति प्रबंधन से संबंधित समस्याओं से बचा जाता है (यदि आपने पॉइंटर्स फेंक दिए) और ऑब्जेक्ट स्लाइसिंग की संभावना के साथ (यदि आप मूल्य से अपवाद पकड़ते हैं)।

0

std::nested_exception और std::throw_with_nested के बाद से सी ++ 11 साथ उपलब्ध हो गए हैं, मैं StackOverflow here पर उत्तर देने के लिए बात करने के लिए चाहते हैं और here

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

वहाँ अपवाद डिजाइन, मेरी राय में, यह भी अपवाद वर्ग पदानुक्रम नहीं बनाने के लिए चलता है, लेकिन के लिए एक ही पुस्तकालय प्रति एक भी अपवाद वर्ग बनाने के (के रूप में पहले से ही an answer to this question में बताया)।

संबंधित मुद्दे