C ++ सभी अपवादों को पकड़ रहा है


244

क्या जावा के बराबर c ++ है

try {
    ...
}
catch (Throwable t) {
    ...
}

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



2
ध्यान दें कि अधिकांश क्रैश C ++ में अपवादों के कारण नहीं होते हैं। आप सभी अपवादों को पकड़ सकते हैं, लेकिन यह कई दुर्घटनाओं को नहीं रोकेगा।
राँभना बतख

जवाबों:


335
try{
    // ...
} catch (...) {
    // ...
}

सभी C ++ अपवादों को पकड़ेंगे, लेकिन इसे खराब डिज़ाइन माना जाना चाहिए। आप c ++ 11 के नए करंट_एक्ससेप्शन मैकेनिज्म का उपयोग कर सकते हैं, लेकिन यदि आपके पास c ++ 11 (लीगेसी कोड सिस्टम को फिर से लिखने की आवश्यकता है) का उपयोग करने की क्षमता नहीं है, तो आपके पास संदेश या नाम प्राप्त करने के लिए उपयोग के लिए कोई अपवाद पॉइंटर नहीं है । आप विभिन्न अपवादों को पकड़ सकते हैं जिन्हें आप पकड़ सकते हैं, और केवल एक अप्रत्याशित अपवाद रिकॉर्ड करने के लिए नीचे की ओर सब कुछ पकड़ सकते हैं। उदाहरण के लिए:

try{
    // ...
} catch (const std::exception& ex) {
    // ...
} catch (const std::string& ex) {
    // ...
} catch (...) {
    // ...
}

68
कॉन्स्ट रेफरेंस द्वारा अपवादों को पकड़ना एक अच्छा अभ्यास है। जैसे: कैच (std :: अपवाद कास्ट एंड एक्स) {/ * ... * /}
coryan

12
@ कोरियन: कॉन्स्ट रेफरेंस द्वारा पकड़ना अच्छा अभ्यास क्यों है?
टिम एमबी

19
अनावश्यक प्रतियों से बचना एक लाभ है।
ग्रेग डी

21
-1: यह सुझाव कि यह "C ++ में सभी अपवादों को पकड़ेगा" भ्रामक है। कोशिश ब्लॉक के अंदर शून्य त्रुटि से एक विभाजन पैदा करने की कोशिश करें। आप देखेंगे कि यह एक अपवाद उत्पन्न करेगा जो पकड़ा नहीं गया है, फिर भी कोड स्पष्ट रूप से C ++ में है। यह बताने में अधिक उपयोगी होगा कि यह "सभी C ++ अपवादों को पकड़ेगा" और फिर सीमित उपयोगिता पर नोटों में संरचित अपवादों के कुछ उल्लेख जोड़ देगा।
ओमताई

42
@omatai: फिक्स्ड, यह सभी C ++ अपवादों को पकड़ लेगा। शून्य द्वारा विभाजन अपरिभाषित व्यवहार है और C ++ अपवाद उत्पन्न नहीं करता है।
मिंग डक

151

किसी को जोड़ना चाहिए कि कोई C ++ कोड में "क्रैश" नहीं पकड़ सकता है। वे अपवाद नहीं फेंकते हैं, लेकिन वे कुछ भी पसंद करते हैं। जब आप एक प्रोग्राम को अशक्त-सूचक उच्चारण के कारण दुर्घटनाग्रस्त होते देखते हैं, तो यह अपरिभाषित व्यवहार कर रहा है। नहीं है std::null_pointer_exception। अपवादों को पकड़ने की कोशिश वहाँ मदद नहीं करेगी।

बस किसी के लिए यह धागा पढ़ रहा है और सोचता है कि वह प्रोग्राम क्रैश का कारण प्राप्त कर सकता है। इसके बजाय gdb जैसे डीबगर का उपयोग किया जाना चाहिए।


4
खैर, जैसा कि शाय बताते हैं, यह वीसी कंपाइलर के साथ संभव है। यह एक अच्छा विचार नहीं है, लेकिन यह संभव है।
शोग

7
हाँ, सेह के साथ। लेकिन नहीं समझदार मानक c ++ तकनीकों के साथ :) अच्छी तरह से अगर आप खिड़कियों से चिपके आप लगभग सब कुछ कर सकते हैं :)
litb - Johannes Schaub

1
हम्म ... इस tidbit के लिए धन्यवाद। मैं इस उत्तर की तलाश में हूँ कि मेरे अशक्त-सूचक अपवादों को क्यों नहीं पकड़ा जा रहा है!
Dalin Seivewright

10
आप विंडोज पर SEH के साथ segfaults और POSIX सिस्टम पर सिग्नल (2) / सिगनेशन (2) को पकड़ सकते हैं, जो आज उपयोग में आने वाले अधिकांश सिस्टम को कवर करता है, लेकिन अपवाद हैंडलिंग की तरह, यह कुछ ऐसा नहीं है जिसे सामान्य प्रवाह नियंत्रण के लिए उपयोग किया जाना चाहिए। यह अधिक है "मरने से पहले कुछ उपयोगी है।"
एडम रोसेनफील्ड

1
@AdamRosenfield जब तक आपने try { .. } catch(...) { ... }सिग्नल / सिगनेशन का उपयोग करते हुए पकड़ने के लिए लागू नहीं किया है, मैं इसे "कैचिंग" नहीं कहूंगा :) यदि सिग्नल हैंडलर में है, तो प्रोग्रामर के लिए यह जानना अपेक्षाकृत कठिन है कि कोड में दुर्घटना कहां हुई (मैं बात कर रहा हूं) कोशिश करने / पकड़ने की तुलना में प्रोग्रामेटिकली उस बारे में पता लगाना)।
जोहान्स शाउब -

72

यह है कि आप catch(...)जीसीसी के साथ अपवाद प्रकार को किस प्रकार से रिवर्स-इंजीनियर कर सकते हैं, जिसकी आपको आवश्यकता है (किसी तीसरे पक्ष के पुस्तकालय से अज्ञात को पकड़ने पर उपयोगी हो सकता है):

#include <iostream>

#include <exception>
#include <typeinfo>
#include <stdexcept>

int main()
{
    try {
        throw ...; // throw something
    }
    catch(...)
    {
        std::exception_ptr p = std::current_exception();
        std::clog <<(p ? p.__cxa_exception_type()->name() : "null") << std::endl;
    }
    return 1;
}

और यदि आप बूस्ट का उपयोग कर सकते हैं तो आप अपने कैच सेक्शन को और भी सरल (बाहर) और संभावित क्रॉस-प्लेटफॉर्म बना सकते हैं

catch (...)
{
    std::clog << boost::current_exception_diagnostic_information() << std::endl;
}

58
try {
   // ...
} catch (...) {
   // ...
}

ध्यान दें कि ...अंदर catchएक वास्तविक दीर्घवृत्त है, अर्थात। तीन डॉट्स।

हालाँकि, क्योंकि C ++ अपवाद अनिवार्य रूप से किसी आधार Exceptionवर्ग के उपवर्ग नहीं हैं, इसलिए वास्तव में अपवाद चर को देखने का कोई तरीका नहीं है जो इस निर्माण का उपयोग करते समय फेंक दिया जाता है।


24
C ++ 11 में है: try {std :: string ()। At (1); // यह एक std :: out_of_range} catch (...) {eptr = std :: current_exception () उत्पन्न करता है; // कैप्चर}
मोहम्मद अलागन

2
@bfontaine: हाँ, लेकिन मैंने कहा कि catchएक टिप्पणी में मौजूदा कोड प्लेसहोल्डर से विनिर्देशक को अलग करने के लिए ( // ...जो स्पष्ट रूप से C ++ सिंटैक्स नहीं है।
ग्रेग हेविगिल

1
@GregHewgill: हाँ, यह सिर्फ टाइपोग्राफिक नाइटपैकिंग था।
bfontaine

1
@ बफोंटेन: फेयर काफी। :)
ग्रेग हेवगिल

44

पोर्टेबल तरीके से सभी अपवादों को पकड़ना संभव नहीं है। ऐसा इसलिए है क्योंकि कुछ अपवाद C ++ संदर्भ में अपवाद नहीं हैं। इसमें शून्य त्रुटियों और अन्य द्वारा विभाजन जैसी चीजें शामिल हैं। के बारे में हैक करना संभव है और इस प्रकार इन त्रुटियों के होने पर अपवादों को फेंकने की क्षमता मिलती है, लेकिन यह करना आसान नहीं है और निश्चित रूप से पोर्टेबल तरीके से सही होना आसान नहीं है।

यदि आप सभी एसटीएल अपवादों को पकड़ना चाहते हैं, तो आप कर सकते हैं

try { ... } catch( const std::exception &e) { ... }

जो आपको उपयोग करने की अनुमति देगा e.what(), जो एक रिटर्न देगा const char*, जो आपको अपवाद के बारे में अधिक बता सकता है। यह वह निर्माण है जो जावा निर्माण से मिलता-जुलता है, आपने इसके बारे में पूछा था।

यह आपकी मदद नहीं करेगा यदि कोई व्यक्ति एक अपवाद फेंकने के लिए पर्याप्त बेवकूफ है जो विरासत में नहीं आता है std::exception


2
यह शीर्ष में क्यों नहीं है?
इवान सन्ज़-कारसा

31

संक्षेप में, का उपयोग करें catch(...)। हालांकि, ध्यान दें कि मूल रूप से catch(...)संयोजन के throw;रूप में उपयोग किया जाना है :

try{
    foo = new Foo;
    bar = new Bar;
}
catch(...)       // will catch all possible errors thrown. 
{ 
    delete foo;
    delete bar;
    throw;       // throw the same error again to be handled somewhere else
}

यह उपयोग करने का उचित तरीका है catch(...)


6
स्मृति प्रबंधन के लिए RAII का उपयोग करना बेहतर है जो स्वचालित रूप से इस अपवाद स्थितियों को संभालता है।
पेकोब

1
@paykoob कैसे उन मामलों को संभालता है जहां आपने एक नया फू बनाने का प्रयास किया था लेकिन यह एक बार में विफल रहा। या जब बार का निर्माता फ़ाइल खोलने की कोशिश करता है, लेकिन विफल रहता है और इसलिए फेंकता है। तो आप एक ख़तरनाक फू के साथ समाप्त हो सकते हैं
मेलस्टर

2
@MelleSterk स्टैक अभी भी उस मामले में साफ नहीं होगा, जो Fooविध्वंसक चलाएगा ? मुझे लगा कि RAII का पूरा बिंदु यही था। हालाँकि, यदि आपको Fooकेवल Fooस्टैक पर बनाने के बजाय एक पॉइंटर की आवश्यकता है , तो आपको पॉइंटर को किसी और चीज़ में लपेटने की आवश्यकता होगी जो स्टैक पर घोषित की गई है।
8

हां ऑटो फू = std :: make_unique <Foo> (); ऑटो बार = std :: make_unique <Bar> (); // अपवाद सुरक्षित है और लीक नहीं होगा, कोई पकड़ (...) की आवश्यकता नहीं है
पॉलम

यह जवाब एक वोट का हकदार है अगर केवल चर्चा के लिए ही शुरू हुआ :)
Cristik

21

यह लिखना संभव है:

try
{
  //.......
}
catch(...) // <<- catch all
{
  //.......
}

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


31
मुझे आशा है कि आपको एक बेहतर उत्तर प्रदान करने के लगभग 5 साल बाद किसी प्रश्न का उत्तर देने के लिए किसी प्रकार का बैज मिला है!

4
@DrEval जैसा कि आप चाहते हैं;) stackoverflow.com/help/badges/17/necromancer?userid=2580505
Andreas

18

आप उपयोग कर सकते हैं

catch(...)

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


1
मैं अभी इनमें से कुछ usages पकड़ा और उस स्तर पर कुछ लॉगिंग में peppered। अपवाद के साथ कुछ नहीं करना निश्चित रूप से परेशानी के लिए पूछ रहा है।
jxramos

15

मुझे सिर्फ यहाँ इसका उल्लेख करना है: जावा

try 
{
...
}
catch (Exception e)
{
...
}

सभी अपवादों को नहीं पकड़ सकते हैं! मैंने वास्तव में इस तरह की बात पहले की है, और यह पागलपन-उत्तेजक है; अपवाद थ्रोएबल से निकलता है। तो सचमुच, सब कुछ पकड़ने के लिए, आप अपवादों को नहीं पकड़ना चाहते; आप थ्रोएबल को पकड़ना चाहते हैं।

मुझे पता है कि यह नाइटपिके लगता है, लेकिन जब आपने कई दिन बिताए हैं यह पता लगाने की कोशिश करें कि "अनकहा अपवाद" कोड में कहां से आया था जो एक कोशिश से घिरा था ... कैच (अपवाद ई) "ब्लॉक आता है, इसके साथ चिपक जाता है आप।


2
बेशक, आपको कभी भी एरर ऑब्जेक्ट्स को नहीं पकड़ना चाहिए - यदि आप उन्हें पकड़ने वाले होते हैं तो वे एक्सेप्शन होंगे। त्रुटि ऑब्जेक्ट पूरी तरह से घातक चीजें हैं, जैसे कि ढेर स्थान से बाहर
भागना

1
न ही रनटाइम अपवाद जो कि ज्यादातर GoodProgrammerExpected अपवाद हैं !!!
ऑस्करराइज

3
हमारे पास वास्तव में एक गंभीर बग था, जो आउटऑफमेमोरी एरर को पकड़ने के कारण पकड़ा गया (थ्रोएबल) ब्लॉक के कारण यह चीजों को मारने देता है ...
ट्रेकजक

1
बेशक catch(Exception)जावा में सभी अपवादों को नहीं पकड़ा जा सकता है, आप इसे C # ... जावा = catch(Thowable), C # = के साथ मिला रहे हैं catch(Exception)। उन्हें भ्रमित मत करो।
शेफ फिरौन

2
@OscarRyz ऐसा लगता है CoderMalfunctionError(जो वास्तव में एक वास्तविक जावा Errorउपवर्ग है ... हालांकि इसका मतलब यह नहीं है कि यह कैसा लगता है।)
रीयरब

9

खैर, अगर आप उदाहरण के लिए एक मिनीडम्प बनाने के लिए सभी अपवादों को पकड़ना चाहते हैं ...

किसी ने विंडोज पर काम किया।

देखें http://www.codeproject.com/Articles/207464/Exception-Handling-in-Visual-Cplus लेख में, वह बताता है कि कैसे उसे सभी प्रकार के अपवादों को पकड़ने का पता चला और वह कोड प्रदान करता है जो काम करता है।

यहाँ सूची है जिसे आप पकड़ सकते हैं:

 SEH exception
 terminate
 unexpected
 pure virtual method call
 invalid parameter
 new operator fault 
 SIGABR
 SIGFPE
 SIGILL
 SIGINT
 SIGSEGV
 SIGTERM
 Raised exception
C++ typed exception

और उपयोग: CCrashHandler ch; ch.SetProcessExceptionHandlers (); // एक थ्रेड के लिए ऐसा करें। SeThreadExceptionHandlers (); // प्रत्येक थ्रेड के लिए


डिफ़ॉल्ट रूप से, यह वर्तमान निर्देशिका में क्रैशडंप बनाता है (crashdump.dmp)


4

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

संदिग्ध। आपको पहले ही पता है कि आपका कोड टूट गया है, क्योंकि यह दुर्घटनाग्रस्त है। अपवादों को खाने से यह नकाब हो सकता है, लेकिन इसका परिणाम शायद नास्टियर, और अधिक सूक्ष्म बग में होगा।

क्या आप वास्तव में चाहते हैं एक डिबगर है ...


13
मैं असहमत हूं, वास्तविक समय के अनुप्रयोगों में बहुत सारे मामले हैं जहां मैं एक अज्ञात अपवाद को पकड़ूंगा, लॉग को कुछ भी लिख सकता हूं / कुछ सामान्य त्रुटि कार्रवाई का पीछा कर सकता हूं , बजाय आवेदन को दुर्घटना के।
16

3
मुझे संदेह है कि आप उन मामलों के बारे में सोच रहे हैं जहां आप कार्रवाई के कुछ सामान्य त्रुटि पाठ्यक्रम का पीछा कर सकते हैं , आसानी से उन लोगों को अनदेखा कर रहे हैं जहां स्टैक को ट्रैश किया गया है या मेमोरी समाप्त हो गई है और सामान्य त्रुटि-हैंडलिंग या तो सफल नहीं हो रही है। त्रुटियों को पकड़ने के साथ कुछ भी गलत नहीं है जिसे आप से पुनर्प्राप्त कर सकते हैं , लेकिन IMHO एक कैच-सभी वास्तव में केवल पृथक (अलग स्टैक, पूर्व-आवंटित मेमोरी) के रूप में मौजूद होना चाहिए, सावधानीपूर्वक लिखित तर्क जिसे प्रोग्राम समाप्ति से पहले कहा जाता है; अगर आपको पता नहीं है कि समस्या क्या है, तो आप आश्वस्त नहीं हो सकते कि इससे उबर लिया जा सकता है।
शोग

1
यानी एक सिग्नल हैंडलर स्थापित करें जो रनटाइम के दौरान आपके द्वारा बनाए गए कुछ लॉग को यह पता लगाने के लिए बनाता है कि प्रोग्राम कहां दुर्घटनाग्रस्त हुआ और, उम्मीद है, क्यों।
साफ

3
  1. क्या आप अपने जेएनआई-उपयोग जावा एप्लिकेशन को एक कंसोल विंडो से चला सकते हैं (इसे एक जावा कमांड लाइन से लॉन्च करें) यह देखने के लिए कि क्या जेवीएम के दुर्घटनाग्रस्त होने से पहले पता लगाया जा सकता है। जावा विंडो एप्लिकेशन के रूप में सीधे चलने पर, आपको ऐसे संदेश गुम हो सकते हैं जो आपके बजाय कंसोल विंडो से चले तो दिखाई देंगे।

  2. दूसरे, क्या आप अपने जेएनआई डीएलएल कार्यान्वयन को यह दिखाने के लिए रोक सकते हैं कि जेएनआई से आपके डीएलएल में तरीके दर्ज किए जा रहे हैं, आप ठीक से लौट रहे हैं, आदि?

  3. बस अगर समस्या C ++ कोड से जेएनआई-इंटरफ़ेस विधियों में से एक के गलत उपयोग के साथ है, तो क्या आपने सत्यापित किया है कि कुछ सरल जेएनआई उदाहरण आपके सेटअप के साथ संकलित और काम करते हैं? मैं विशेष रूप से जेएनआई-इंटरफ़ेस के तरीकों को देशी सी ++ प्रारूपों में परिवर्तित करने और जावा परिणामों में फ़ंक्शन परिणामों को बदलने के लिए सोच रहा हूं। यह सुनिश्चित करने के लिए कि डेटा रूपांतरण काम कर रहे हैं और आप JNI इंटरफ़ेस में COM जैसी कॉल में हाइयर नहीं जा रहे हैं, उन्हें स्टब करना उपयोगी है।

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


2

JNI का उपयोग करने वाले प्रोग्राम को ठीक से डिबग करने में असमर्थ होने के बारे में वास्तविक समस्या के लिए (या डीबगर के नीचे चलने पर बग दिखाई नहीं देता है):

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

यह अक्सर वास्तविक त्रुटि को खोजने में मदद करेगा (जो आश्चर्यजनक रूप से ज्यादातर जावा कोड में होता है जो कॉल किए गए कार्यों के शब्दार्थों का पालन नहीं करता है जो कुछ बुरा डबल-फ्रीज़ या इसी तरह के कारण होते हैं) अधिक आसानी से एक समानांतर समानांतर जावा प्रोग्राम को डीबग करने की कोशिश में देशी डीबगर ...

यदि आप इसका कारण जानते हैं, तो कोड को अपने आवरण विधियों में रखें जो इसे टालता है। बेहतर है कि आपके जेपीआई कोड की तुलना में आपके रैपर तरीकों के अपवादों को वीएम क्रैश कर दे ...


1

खैर यह वास्तव में संकलक वातावरण पर निर्भर करता है। gcc इन्हें नहीं पकड़ता है। विजुअल स्टूडियो और आखिरी बोरलैंड जो मैंने इस्तेमाल किया था।

तो दुर्घटनाओं के बारे में निष्कर्ष यह है कि यह आपके विकास पर्यावरण की गुणवत्ता पर निर्भर करता है।

C ++ विनिर्देशन कहता है कि पकड़ (...) को किसी भी अपवाद को पकड़ना चाहिए, लेकिन यह सभी मामलों में नहीं है।

कम से कम मैंने जो कोशिश की थी।


1

जागरूक रहें

try{
// ...
} catch (...) {
// ...
}

केवल भाषा-स्तरीय अपवादों को पकड़ता है, अन्य निम्न-स्तरीय अपवादों / त्रुटियों जैसे Access Violationऔर Segmentation Faultअभ्यस्त को नहीं पकड़ा जाता है।


सेग्मेंटेशन फॉल्ट जैसी चीजें वास्तव में अपवाद नहीं हैं, वे संकेत हैं; इस प्रकार, आप उन्हें विशिष्ट अपवादों की तरह नहीं पकड़ सकते। हालाँकि, इस तरह के कुछ वर्कअराउंड हैं ।
मचिट्ठार्ग
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.