2009-02-18 29 views
25

क्या अपवाद प्रकार निर्धारित करने का कोई तरीका है, यह भी पता है कि आपने कैच के साथ अपवाद पकड़ा है?अपवाद के बाद अपवाद प्रकार निर्धारित करना पकड़ा गया है?

उदाहरण:

try 
{ 
    SomeBigFunction(); 
} 
catch(...) 
{ 
    //Determine exception type here 
} 
+0

क्या आप समझ सकते हैं कि आपको इसकी आवश्यकता क्यों है? शायद हम विकल्पों के लिए देख सकते हैं? –

+0

मैं स्पष्ट रूप से स्क्रैच से कुछ कोडिंग नहीं करता हूं, लेकिन विशिष्ट परिस्थितियों में मैं इसके तहत उपयोगी हूं। लीगेसी कोड। –

उत्तर

19

आप actully एक पकड़ने (...) के अंदर प्रकार का निर्धारण कर सकते हैं, लेकिन यह बहुत उपयोगी नहीं है:

#include <iostream> 
#include <exception> 

    class E1 : public std::exception {}; 
    class E2 : public std::exception {}; 

    int main() { 
     try { 
      throw E2(); 
     } 
     catch(...) { 
      try { 
       throw; 
      } 
      catch(const E1 & e) { 
       std::cout << "E1\n"; 
      } 
      catch(const E2 & e) { 
       std::cout << "E2\n"; 
      } 
     } 
    } 
+3

यह तकनीक वास्तव में उपयोगी हो सकती है यदि 'try {throw; } '... भाग एक समारोह में है जिसे 'कैच (...)' ब्लॉक में बुलाया जाता है। – wjl

+1

यह तकनीक * वास्तव में उपयोगी है। 'पकड़ (...) 'में अपवाद हैंडलर को कॉल करने के बारे में सोचें। अपवाद हैंडलर फिर से फेंकता है और इस तकनीक के साथ प्रकार निर्धारित करता है। यह असामान्य (अपवाद) कोड पथ से सामान्य कोड पथों को अलग करने की अनुमति देता है। – user23573

1

सं

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

एक बार आपके पास अपवाद उदाहरण था, तो आपको एक प्रकार का निरीक्षण एल्गोरिदम का उपयोग करना होगा। सी ++ के लिए निहित समर्थन नहीं है। सबसे अच्छे रूप में आपको टाइप करने के लिए गतिशील_कास्ट के साथ/elseif कथन का बड़ा होना होगा।

5

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

25

लघु उत्तर: नहीं।

लांग उत्तर:

आप एक आम आधार प्रकार से अपने सभी अपवादों को निकाले जाते हैं (std :: अपवाद कहते हैं) और इस स्पष्ट रूप से पकड़ तो आप इस का उपयोग कर सकते प्रकार प्राप्त करने के लिए आपके अपवाद से जानकारी।

लेकिन आपको विशिष्ट प्रकार के अपवाद के रूप में पकड़ने के लिए पकड़ने की सुविधा का उपयोग करना चाहिए और फिर वहां से काम करना चाहिए।

पकड़ (...) के लिए केवल वास्तविक इस्तेमाल होता है:

  • पकड़ने: और दूर अपवाद फेंक (बंद अपवाद नाशक बचने)।
  • कैच: एक अनजान अपवाद लॉग इन करें और फिर से फेंक दें।

संपादित: आप dynamic_cast <>() या typid के माध्यम से के माध्यम से प्रकार की जानकारी निकाल सकते हैं() हालांकि के रूप में इस ऊपर कहा गया है somthing मैं सिफारिश नहीं है। केस स्टेटमेंट का प्रयोग करें।

#include <stdexcept> 
#include <iostream> 

class X: public std::runtime_error // I use runtime_error a lot 
{         // its derived from std::exception 
    public:       // And has an implementation of what() 
     X(std::string const& msg): 
      runtime_error(msg) 
     {} 
}; 

int main() 
{ 
    try 
    { 
     throw X("Test"); 
    } 
    catch(std::exception const& e) 
    { 
     std::cout << "Message: " << e.what() << "\n"; 

     /* 
     * Note this is platform/compiler specific 
     * Your milage may very 
     */ 
     std::cout << "Type: " << typeid(e).name() << "\n"; 
    } 
} 
+0

इस मामले में कैच के साथ यह कैसे काम करेगा? – JaredPar

+0

यह स्पष्ट करने के लिए संपादित किया गया है कि आपको आधार अपवाद को पकड़ने की आवश्यकता होगी। –

+0

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

-2

आप विज़ुअल सी उपयोग कर रहे हैं ++ (प्रबंधित), तो आप उपयोग कर सकते हैं अपवाद के प्रकार को प्राप्त करने के लिए GetType() विधि और इसे वहां से संभाल लें।

उदा।

try 
    { 
     // Run the application 
     Application::Run(mainForm); 
    } 
    catch (Exception^ e) 
    { 
     String^ exception_type = e->GetType()->ToString(); 
     throw; 
    } 

स्ट्रिंग में "System.ArgumentOutOfRangeException" जैसी कुछ चीज़ें शामिल होंगी।

+5

यह सी ++ नहीं है। यह सी ++/सीएलआई है। जो .NET रनटाइम के लिए ज्यादातर एक सी ++ वाक्यविन्यास है। यह सी ++ कार्यक्षमता प्रदान करता है, लेकिन सीएलआई भाग सी ++ से बिल्कुल अलग है। – Eonil

0

मैंने कई तरीकों से प्रयास किया है; यह मेरे लिए काम करता है:

उपवर्गीकरण द्वारा शुरू runtime_error:

/*----------------------------------------------------------------------*/  
/* subclass runtime_error for safe exceptions in try/throw/catch  */ 

#include <stdexcept> 
/* a little preprocessor magic here -- makes a subclass of runtime_error*/ 

#define NEWERROR(NE) class NE : public runtime_error {    \ 
     public: NE (string const& error) : runtime_error(error) {} } 


NEWERROR(FileError  ); 
NEWERROR(NetworkError ); 
NEWERROR(StringError ); 
NEWERROR(CofeeError ); 

/*----------------------------------------------------------------------*/ 

तो फिर आप अपने अपवादों में से कुछ उदाहरणों बना सकते हैं।

/*----------------------------------------------------------------------*/ 
/* some example pre-defined exceptions */ 

FileError  ReadOnly    ("ReadOnly"   ); 
FileError  FileNotFound   ("FileNotFound"  ); 
NetworkError TimeOutExceeded   ("TimeOutExceeded"  ); 
NetworkError HostNotFound   ("HostNotFound"  ); 
CoffeeError OutOfCoffee    ("OutOfCoffee"   ); 

/*----------------------------------------------------------------------*/ 

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

"सुनिश्चित करें कि आप कुछ भी पकड़ सकते हैं जो आप फेंक सकते हैं।"

(मैं सामान्य runtime_error उपयोग करें, क्योंकि फेंक और इसे पकड़ने मेरी अपवाद प्लस प्रणाली 'लोगों के सभी के साथ-साथ शामिल किया गया।)

/*----------------------------------------------------------------------*/ 
/* example function that may throw an exception */ 

#include <fstream> 

ifstream& getFileStream (string fname) throw (runtime_error) 
{ 

    if (fname == "") 
     throw StringError("<getFileStream> fname:empty string"); 
     // processing stops here if thrown 

    try 
     { 
     ifstream Inputfstream; 

     ifstream& ifsref = Inputfstream; 

     // ifstream has its own <legacy> exception 
     // mechanisms and procedures 
     ifsref.exceptions (ifstream::failbit | ifstream::badbit); 

     ifsref.open (fname , ifstream::in); // could fail ==> ifstream::failure exception 
     } 
    catch (ifstream::failure e) 
     { 
     throw FileError(fname + string(e.what())); 
     } 

    return ifsref; 
} 

/*----------------------------------------------------------------------*/ 
फिर अपने ट्राई/कैच में

/*----------------------------------------------------------------------*/ 
catch (FileNotFound fnf) //catch a specific error 
{ 
    if (DEBUG) cerr << "[File Not Found Error: " << fnf.what() << "]" << endl; 
    ... (handle it) ... 
} 
catch (FileError fe) //catch a specific type 
{ 
    if (DEBUG) cerr << "[File Error: " << fe.what() << "]" << endl; 
    ... (handle it) ... 
} 
catch (runtime_error re) // catch a generic type 
{ 
    if (DEBUG) cerr << "[Runtime error: " << re.what() << "]" << endl;   

    // determine type by string comparison 
    if (re.what() == string("ResourceNotavailable")) ... 
    if (re.what() == string("NetWorkError")  ) ... 

    ... 

} 
catch (...) // catch everything else 
{ ... exit, rethrow, or ignore ... } 

/*----------------------------------------------------------------------*/ 

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

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

  • तर्क त्रुटियों:

    logic_error 
    domain_error 
    invalid_argument 
    length_error 
    out_of_range 
    
  • क्रम त्रुटियों:

    runtime_error 
    range_error 
    overflow_error 
    underflow_error 
    

उपयोग वाक्य रचना

<stdexcept> 2 समूहों में आप अपवाद के कई प्रकार देता है उनमें से कुछ के लिए थोड़ा अलग है। C++

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

अन्त में, मेरे प्वाइंट है: आप फेंकने से इस सब को प्राप्त करने और केवल पकड़ने runtime_error कर सकते हैं।

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

+0

हम्म .. अपवादों के प्रकार को निर्दिष्ट करते हुए एक विधि फेंकने को थोड़ी देर के लिए हटा दिया गया है। –

+0

हां, तो यह कहता है। लेकिन वास्तव में कुछ समस्याएं हैं जो अपवाद प्रकार निर्दिष्ट नहीं करने के साथ स्पष्ट नहीं हो सकती हैं। समस्या यह है कि हकीकत में, कोई भी विधि कुछ भी फेंक सकती है: int, char *, ऑब्जेक्ट्स, आदि यदि आप उस विधि को निर्दिष्ट करते हैं जो एक्स फेंकता है (ए, बी, सी) और फिर यह कुछ और फेंकता है (जैसे मॉलोक त्रुटि) std :: अप्रत्याशित रूप से एक हैंडलर विधि की तलाश करने या std :: समाप्त करने के लिए बुलाया जाता है। या यदि आप केवल खाली फेंक() क्लॉज के साथ एक विधि घोषित करते हैं तो std :: अप्रत्याशित किसी अपवाद पर बुलाया जाता है। –

1

ऐसा करने के लिए कोई मानक, पोर्टेबल तरीका नहीं है। यहाँ एक गैर पोर्टेबल जीसीसी और बजना पर यह करने के लिए रास्ता नहीं है

#include <iostream> 
#include <cxxabi.h> 

const char* currentExceptionTypeName() 
{ 
    int status; 
    return abi::__cxa_demangle(abi::__cxa_current_exception_type()->name(), 0, 0, &status); 
} 

int main() 
{ 
    try { 
     throw std::string(); 
    } catch (...) { 
     std::cout<<"Type of caught exception is "<<currentExceptionTypeName()<<std::endl; 
    } 

    return 0; 
} 

आउटपुट:

Type of caught exception is std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > 
0

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

#include <iostream> 
#include <exception> 

class E1 : public std::exception {}; 
class E2 : public std::exception {}; 
class E3 : public std::exception {}; 

int main() { 
    try { 
     throw E3(); 
    } 
    catch(...) { 
     try { 
      // OOOPS!!! E3 is now unhandled!!!!!! 
      throw; 
     } 
     catch(const E1 & e) { 
      std::cout << "E1\n"; 
     } 
     catch(const E2 & e) { 
      std::cout << "E2\n"; 
     } 
    } 
} 

इस दृष्टिकोण के लिए एक वैकल्पिक होगा मुझे उत्तरदाता के जवाब का निर्माण करते हैं निम्नलिखित:

#include <iostream> 
#include <exception> 

class E1 : public std::exception {}; 
class E2 : public std::exception {}; 
class E3 : public std::exception {}; 

int main() { 
    try { 
     throw E3(); 
    } 
    catch(const E1 & e) { 
     std::cout << "E1\n"; 
    } 
    catch(const E2 & e) { 
     std::cout << "E2\n"; 
    } 
    catch(...) { 
     std::cout << "Catch-all..."; 
    } 
} 

यह दूसरा दृष्टिकोण पहले के समान प्रतीत हो रहा है और विशेष रूप से का लाभ दिया है E1 और E2 को संभालने और फिर बाकी सब कुछ पकड़ना। यह केवल एक विकल्प के रूप में पेश किया जाता है।

कृपया ध्यान दें कि, सी ++ 2011-02-28 के ड्राफ्ट, पैरा 15.3, बुलेट आइटम 5 के अनुसार, "तो मौजूद है, एक ... हैंडलर इसकी कोशिश ब्लॉक के लिए पिछले हैंडलर होगा।"

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