फेंक नई एसटीडी :: अपवाद बनाम एसटीडी एसटी :: अपवाद


113

कुछ कोड को देखने के दौरान मैंने ठोकर खाई:

throw /*-->*/new std::exception ("//...

और मुझे हमेशा लगता था कि आपको ज़रूरत नहीं है / आपको newयहाँ उपयोग नहीं करना चाहिए ।
क्या सही तरीका है, क्या दोनों ठीक हैं, अगर ऐसा है तो क्या कोई अंतर है?

पावरशेल बूस्ट लिब के साथ "ग्रेपिंग" करते समय मैं जो कुछ भी देख सकता हूं उससे बीटीडब्ल्यू कभी उपयोग नहीं करते हैं throw new

PS मुझे कुछ CLI कोड भी मिला जो उपयोग करता है throw gcnew। क्या वह ठीक है?


1
मुझे लगता है throw gcnewकि यह उपयोगी होगा। यदि आप अपने अपवाद को पकड़ने के लिए प्रबंधित कोड चाहते हैं। क्या कोई मुझे उस पर सही कर सकता है?
jpalecek

1
.Net सूचक द्वारा अपवादों से संबंधित है, इसलिए gcnew फेंकना सही काम है।
सेबस्टियन रेडल

1
@SebastianRedl .Net "पॉइंटर" अस्पष्ट हो सकता है? हालांकि निश्चित रूप से gcnew नहीं है। System::Exceptionआम तौर पर एकत्रित कचरे के ढेर पर एक प्रबंधित वस्तु का संदर्भ है। मैंने हमेशा साथ फेंका है gcnewऔर पकड़ा है System::Exception ^। बेशक, मैं finallyसी ++ / सीएलआई में हर समय उपयोग करता हूं , हालांकि अक्सर एक ही tryब्लॉक में सी ++ अपवादों के साथ मिश्रण नहीं करते हैं , मुझे यकीन नहीं है कि क्यों।

जवाबों:


89

अपवादों को फेंकने और पकड़ने का पारंपरिक तरीका एक अपवाद वस्तु को फेंकना और इसे संदर्भ (आमतौर पर constसंदर्भ) द्वारा पकड़ना है । C ++ भाषा को अपवाद वस्तु के निर्माण के लिए उपयुक्त कोड उत्पन्न करने और उचित समय पर इसे ठीक से साफ करने के लिए कंपाइलर की आवश्यकता होती है।

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

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

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


1
"एक अपवाद वस्तु फेंकें" मेरे मित्र को ढेर या ढेर कर दें? ढेर या ढेर? (शायद मैं कहीं खराब वैश्विक उदाहरण देख रहा था) ओह और अगर स्टैक है, तो उपयुक्त गुंजाइश क्या है?

@ebyrob: मैं वास्तव में निश्चित नहीं हूं कि आप किस बारे में पूछ रहे हैं, लेकिन लगता है कि आप अपवाद वस्तु के भंडारण और / या जीवनकाल के बारे में जानना चाहते हैं जिसका जवाब यहां दिया जा सकता है । यदि आप एक अलग सवाल पूछ बेहतर नहीं हो सकता है।
सीबी बेली

31

newअपवाद फेंकने पर उपयोग करने की कोई आवश्यकता नहीं है।

बस लिखें:

throw yourexception(yourmessage);

और के रूप में पकड़:

catch(yourexception const & e)
{
      //your code (probably logging related code)
}

ध्यान दें कि प्रत्यक्ष या अप्रत्यक्ष रूप yourexceptionसे प्राप्त करना चाहिए std::exception


7
क्यों? उपयोग क्यों नहीं new? क्यों प्राप्त yourexceptionकिया std::exception?
वाल्टर

जब मैं आलसी होता हूं (जो अक्सर होता है) तो throw std::exception;काम क्यों नहीं करता? g ++ इसे संकलित नहीं करेगा ...

7
@ebyrob: std::exceptionएक प्रकार है, और आप एक प्रकार फेंक नहीं सकते , आप एक वस्तु फेंक सकते हैं । तो सिंटैक्स यह होना चाहिए: throw std::exception();जो संकलन करेगा। अब यह कितना अच्छा है, एक अलग सवाल है।
नवाज

22

new std::exceptionयदि कॉल साइट को पकड़ने की उम्मीद है तो थ्रोइंग सही है std::exception*। लेकिन कोई भी एक अपवाद के लिए एक संकेतक को पकड़ने की उम्मीद नहीं करेगा। यहां तक ​​कि अगर आप दस्तावेज बनाते हैं कि आपका कार्य क्या करता है और लोग दस्तावेज़ीकरण पढ़ते हैं, तो वे अभी भी भूलने के लिए उत्तरदायी हैं और std::exceptionइसके बजाय किसी ऑब्जेक्ट के संदर्भ को पकड़ने की कोशिश करते हैं।


27
फेंकना new std::exceptionकेवल तभी सही है जब कॉल साइट एक पॉइंटर को पकड़ने की उम्मीद कर रही है और आवंटित अपवाद के प्रबंधन को संभालने की उम्मीद कर रही है और कभी भी ऐसे मामले नहीं होने जा रहे हैं जहां आप कार्य करेंगे, ऐसा कुछ कहा जाएगा जो स्पष्ट रूप से पकड़ में नहीं आता है सही सूचक ( catch(...)या बिल्कुल नहीं संभालना) अन्यथा एक वस्तु रिसाव होगा। संक्षेप में, यह "कभी नहीं" के रूप में अनुमानित किया जा सकता है।
सीबी बेली

यह उत्सुक है कि यह उत्तर कैसे स्वीकार किया गया, जब वास्तव में यह @ चार्ल्सबेली की टिप्पणी है जो सही उत्तर है।
जॉन डिब्लिंग

@ जॉन: यह मेरे मन को भी पार कर गया। लेकिन मुझे लगता है कि एक-दो पंच का मेरे साथ अच्छा प्रभाव है और यह सूखा सारांश दे रहा है और चार्ल्स विभिन्न तरीकों पर विस्तार कर रहे हैं जिससे लोग ठीक से निपटने के लिए भूल जाते हैं। बहुत बुरा आप ऊपर-नीचे टिप्पणियों से प्रतिष्ठा प्राप्त नहीं करते हैं, हालांकि।

चार्ल्स ने अपना उत्तर नहीं दिया, और इस A (अन्य के विपरीत) में A और टिप्पणी दोनों में स्पष्टीकरण हैं।
NoSenseEtAl

9

C ++ FAQ में इस पर अच्छी चर्चा है:

  1. https://isocpp.org/wiki/faq/exceptions#what-to-catch
  2. https://isocpp.org/wiki/faq/exceptions#catch-by-ptr-in-mfc

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


2
सामान्य रूप से अक्सर पूछे जाने वाले प्रश्न बुरी तरह से लिखे जाते हैं। आप मूल्य या संदर्भ से पकड़ सकते हैं। एक पॉइंटर केवल एक मान होता है (जिसे आप वैल्यू या रेफरेंस द्वारा पकड़ते हैं)। याद रखें कि प्रकार प्रकार Aसे अलग है A*इसलिए यदि मैं करूं तो throw A()मैं इसे पकड़ नहीं सकता catch(A* e)क्योंकि यह पूरी तरह से अलग प्रकार है।
मार्टिन यॉर्क

ये लिंक अब टूट गया है।
Stephenspann

1
मैंने लिंक @spanndemic
user1202136

1

ऑपरेटर नया गारंटी नहीं दे सकता है कि वह कभी भी अपवाद नहीं उठाएगा। इस कारण से "वैध" (इच्छित) अपवाद को फेंकने के लिए इसका उपयोग एक ऐसे कोड का उत्पादन करेगा जिसकी गारंटी नहीं दी जा सकती कि दुर्घटना न हो। चूंकि एक समय में केवल एक अपवाद हो सकता है, और आपका प्रोग्राम उनमें से किसी को भी पकड़े जाने से पहले दो फेंकने की कोशिश करता है, एक कार्यान्वयन जो सबसे अच्छी चीज कर सकता है वह है अपने प्रोग्राम को तुरंत निरस्त करना, जैसे कि std :: terminate कहकर।

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