2009-09-26 21 views
19

कोड के दो समान टुकड़े की कल्पना कीजिए:पकड़े गए अपवाद के तर्क के साथ फेंकने और फेंकने के बीच क्या अंतर है?

try { 
    [...] 
} catch (myErr &err) { 
    err.append("More info added to error..."); 
    throw err; 
} 

और

try { 
    [...] 
} catch (myErr &err) { 
    err.append("More info added to error..."); 
    throw; 
} 

इन प्रभावी ढंग से एक ही कर रहे हैं या वे कुछ सूक्ष्म तरीके से अलग है? उदाहरण के लिए, क्या पहला व्यक्ति एक कॉपी कन्स्ट्रक्टर को चलाने का कारण बनता है, जबकि दूसरा दूसरा वही ऑब्जेक्ट पुन: उत्पन्न करने के लिए पुन: उपयोग करता है?

उत्तर

26

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

एक नो-तर्क फेंक अभिव्यक्ति, वर्तमान अपवाद वस्तु की गतिशील प्रकार संरक्षण फेंक जबकि एक तर्क के साथ एक फेंक अभिव्यक्ति स्थिरthrow को तर्क के प्रकार के आधार कोई नया अपवाद फेंक देंगे।

उदा।

int main() 
{ 
    try 
    { 
     try 
     { 
      throw Derived(); 
     } 
     catch (Base& b) 
     { 
      std::cout << "Caught a reference to base\n"; 
      b.print(std::cout); 
      throw b; 
     } 
    } 
    catch (Base& b) 
    { 
     std::cout << "Caught a reference to base\n"; 
     b.print(std::cout); 
    } 

    return 0; 
} 

जैसा कि ऊपर लिखा है, कार्यक्रम होगा उत्पादन:

Caught a reference to base 
Derived 
Caught a reference to base 
Base

हैं throw b, एक throw के साथ बदलें तब बाहरी पकड़ भी मूल रूप से फेंक दिया Derived अपवाद पकड़ेगा है। यह अभी भी रखता है कि आंतरिक कक्षा Base संदर्भ के बजाय मूल्य द्वारा अपवाद को पकड़ती है - हालांकि स्वाभाविक रूप से इसका मतलब यह होगा कि मूल अपवाद वस्तु को संशोधित नहीं किया जा सकता है, इसलिए b में कोई भी परिवर्तन बाहरी ब्लॉक द्वारा पकड़े गए Derived अपवाद में दिखाई नहीं देगा ।

+1

आह, मैं पूरी तरह से टुकड़ा करने के बारे में भूल गया! डेमिट, यह महत्वपूर्ण है! इस बात की जानकारी देने के लिए धन्यवाद। +1 (हालांकि मुझे लगता है कि जब आपने लिखा था ... ... मूल स्थैतिक प्रकार को संरक्षित करना ... "आपका मतलब _dynamic_ प्रकार था। _dynamic type_ कहलाता है, आखिरकार, यदि _" मूल स्थैतिक प्रकार "_ नहीं है) - – sbi

+1

ग्रेट जवाब, मैं भी इसके बारे में पूरी तरह से भूल गया। – GManNickG

+0

मुझे खुशी है कि किसी और ने _slicing_ समस्या में भाग लिया है;) –

16

सी ++ स्टैंडर्ड 15.1/6 प्रतिलिपि निर्माता के अनुसार दूसरे मामले में नहीं किया जाता है:

कोई संकार्य के साथ एक थ्रो-अभिव्यक्ति rethrows अपवाद संभाला जा रहा। अपवाद मौजूदा अस्थायी के साथ पुनः सक्रिय है; कोई नई अस्थायी अपवाद वस्तु नहीं बनाई गई है। अपवाद अब पकड़ा नहीं माना जाता है; इसलिए, uncaught_exception() का मान फिर से सच होगा।

पहला मामला नया अपवाद में 15.1/3 के अनुसार फेंक दिया जाएगा:

एक थ्रो-अभिव्यक्ति एक अस्थायी वस्तु initializes, अपवाद वस्तु है, जो के प्रकार के किसी भी हटाने के द्वारा निर्धारित किया जाता है कहा जाता है फेंकने के संचालन के स्थिर प्रकार से 0 -"क्रमशः टी" या "फ़ंक्शन रिटर्निंग टी" से "पॉइंटर टू टी" या "ट्रिगर रिटर्निंग टी के सूचक" क्रमशः से टाइप करने के स्थिर प्रकार से शीर्ष स्तर के सीवी-क्वालीफायर। < ...> अस्थायी का उपयोग मिलान वाले हैंडलर (15.3) में नामित चर को प्रारंभ करने के लिए किया जाता है। फेंक-अभिव्यक्ति का प्रकार अपूर्ण प्रकार, या शून्य *, कॉन्स शून्य *, अस्थिर शून्य *, या कॉन्स अस्थिर शून्य * के अलावा अधूरा प्रकार का सूचक या संदर्भ नहीं होगा। इन प्रतिबंधों और पर प्रतिबंधों को छोड़कर 15.3 में उल्लिखित मिलान मिलान, फेंकने के संचालन को (5.2.2) या रिटर्न स्टेटमेंट के संचालन में फ़ंक्शन तर्क के रूप में बिल्कुल ठीक माना जाता है।

दोनों ही मामलों में नकल निर्माता फेंक मंच (15.1/5) की आवश्यकता नहीं है:

जब फेंका वस्तु एक वर्ग वस्तु है, और प्रतिलिपि अस्थायी प्रतिलिपि को प्रारंभ करने के लिए इस्तेमाल निर्माता सुलभ नहीं है , कार्यक्रम खराब गठित है (यहां तक ​​कि जब अस्थायी वस्तु अन्यथा समाप्त हो सकती है)। इसी तरह, यदि उस वस्तु के लिए विनाशक पहुंच योग्य नहीं है, तो कार्यक्रम खराब हो गया है (भले ही अस्थायी वस्तु अन्यथा समाप्त हो सके)।

+0

चूंकि कॉपी सीटीओ को मूल रूप से फेंकने वाले अपवाद के लिए सुलभ होने की आवश्यकता है, इसलिए मुझे नहीं लगता कि यह इस मामले में एक मुद्दा है। लेकिन आपका अभी भी एक अच्छा जवाब है। +1 – sbi

+0

हां, लेकिन पहले मामले में कॉपी सी-टोर दो बार उपयोग किया जाएगा। –

+1

यह कहता है कि जब घोषणा कक्षा प्रकार निर्दिष्ट करती है। हालांकि उनके मामले में यह एक संदर्भ प्रकार निर्दिष्ट करता है :) संदर्भ सीधे बाध्य होगा और अपवाद वस्तु का संदर्भ लेंगे। इसलिए, हमें फेंकने के बिंदु पर केवल एक कॉपी सीटीओ की आवश्यकता होगी, इस मामले में नहीं पकड़ना (उदाहरण के लिए, बेस कॉपी कन्स्ट्रक्टर संरक्षित होने पर यह एक फर्क पड़ेगा)। –

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