C ++ अपवाद हैंडलिंग रनटाइम कैसे लागू किया जाता है?


84

मैं C ++ अपवाद हैंडलिंग तंत्र कैसे काम करता है, इसके बारे में बता रहा हूं। विशेष रूप से, अपवाद ऑब्जेक्ट कहाँ संग्रहीत किया जाता है और इसे पकड़े जाने तक कई स्कोप के माध्यम से कैसे फैलता है? क्या यह किसी वैश्विक क्षेत्र में संग्रहीत है?

चूंकि यह संकलक विशिष्ट हो सकता है इसलिए कोई इसे g ++ संकलक सूट के संदर्भ में समझा सकता है?


4
इस लेख को पढ़ें आपकी मदद करेंगे
अहमद ने

मुझे नहीं पता - लेकिन मैं अनुमान लगा रहा हूं कि सी ++ कल्पना की एक स्पष्ट परिभाषा है। (हालांकि मैं गलत हो सकता हूं)
पॉल नाथन

2
नहीं, युक्ति परिभाषा नहीं देती है। यह व्यवहार को निर्देशित करता है, कार्यान्वयन नहीं। पॉल, आप निर्दिष्ट करना चाह सकते हैं कि आप किस कार्यान्वयन में रुचि रखते हैं।
रोब कैनेडी

1
संबंधित प्रश्न: stackoverflow.com/questions/307610/…
CBSB

जवाबों:


49

कार्यान्वयन भिन्न हो सकते हैं, लेकिन कुछ बुनियादी विचार हैं जो आवश्यकताओं से अनुसरण करते हैं।

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

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

दूसरी रणनीति इस जानकारी को स्टैक के बाहर तालिकाओं में ले जाती है। अब, जब कोई अपवाद होता है, तो कॉल स्टैक का उपयोग यह पता लगाने के लिए किया जाता है कि कौन से स्कोप दर्ज किए गए हैं लेकिन बाहर नहीं निकले। फिर स्थिर तालिकाओं में देखा जाता है कि यह निर्धारित करने के लिए कि फेंके गए अपवाद को कहां संभाला जाएगा, और बीच में कौन से विध्वंसक चलते हैं। इसका मतलब है कि स्टैक पर ओवरहेड कम अपवाद है; रिटर्न पते वैसे भी आवश्यक हैं। टेबल अतिरिक्त डेटा हैं, लेकिन कंपाइलर उन्हें प्रोग्राम के एक मांग-भार वाले सेगमेंट में डाल सकते हैं।


4
AFAIR g ++ दूसरे, एड्रेस-टेबल अप्रोच का उपयोग करता है, संभवतः C के साथ संगतता के कारणों के लिए। Microsoft C ++ कंपाइलर एक संयुक्त दृष्टिकोण का उपयोग करता है, क्योंकि इसके C ++ अपवाद एसईएच (संरचित अपवाद हैंडलिंग) के शीर्ष पर बने हैं। प्रत्येक C ++ फ़ंक्शन में, MSC ++ एक SEH अपवाद-हैंडलिंग रिकॉर्ड बनाता है और पंजीकृत करता है, जो इस विशेष फ़ंक्शन में ट्राइ-कैच ब्लॉक और डिस्ट्रक्टर्स के लिए पता पर्वतमाला के साथ एक तालिका को इंगित करता है। एक SE ++ अपवाद के रूप में C ++ अपवाद को फेंकते हैं और RaiseException () को कॉल करते हैं, तो SEH C ++ - विशिष्ट हैंडलर रूटीन पर नियंत्रण लौटाता है।
एंटन टायखी

1
@ एटन: हाँ, यह एड्रेस-टेबल दृष्टिकोण का उपयोग करता है। विवरण के लिए stackoverflow.com/questions/307610/… पर एक अन्य प्रश्न का मेरा उत्तर देखें।
सीजरबी

जवाब के लिए धन्यवाद। आप देख सकते हैं कि C शुद्धतावादी C ++ और उसके अपवादों से कैसे भयभीत हो सकते हैं। यह विचार कि एक साधारण कोशिश / कैच अनजाने में कई स्टैक ऑब्जेक्ट्स रनटाइम पर बना सकता है या आपके प्रोग्राम को अतिरिक्त टेबल के साथ ब्लोट कर सकता है यही कारण है कि एम्बेडेड सिस्टम अक्सर उनसे बचते हैं।
स्पीडप्लेन

@speedplane: नहीं, यह समझ की कमी के कारण अधिक है। त्रुटि से मुक्त कभी नहीं है। C आपको इसे स्वयं लिखने के लिए बाध्य करता है। और हम सभी जानते हैं कि कितने सी प्रोग्राम एक free()या fclose()कुछ शायद ही कभी इस्तेमाल किए गए कोड पथ में गायब हैं ।
7

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

20

इसे 15.1 में परिभाषित किया गया है जो मानक का अपवाद है।

फेंक एक अस्थायी वस्तु बनाता है।
इस अस्थायी ऑब्जेक्ट के लिए मेमोरी कैसे आवंटित की जाती है अनिर्दिष्ट है।

अस्थायी ऑब्जेक्ट के निर्माण के बाद कॉल स्टैक में निकटतम हैंडलर को पास किया जाता है। थ्रो और कैच पॉइंट के बीच स्टैक को खोलना। जैसा कि स्टैक को खोल दिया गया है किसी भी स्टैक चर को निर्माण के रिवर्स ऑर्डर में नष्ट कर दिया जाता है।

जब तक अपवाद फिर से नहीं फेंका जाता है तब तक अस्थायी हैंडलर के अंत में नष्ट हो जाता है जहां इसे पकड़ा गया था।

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

S.Meyers से सलाह (कॉन्स्ट रेफरेंस द्वारा कैच)।

try
{
    // do stuff
}
catch(MyException const& x)
{
}
catch(std::exception const& x)
{
}

3
अनिर्दिष्ट कुछ और है कि कैसे प्रोग्राम स्टैक को खोल देता है और कैसे प्रोग्राम जानता है कि "निकटतम हैंडलर" कहां है। मुझे पूरा यकीन है कि बोरलैंड इसे लागू करने के एक तरीके पर एक पेटेंट रखता है।
रॉब कैनेडी

जब तक वस्तुओं को निर्माण के रिवर्स ऑर्डर में नष्ट नहीं किया जाता है तब तक कार्यान्वयन विवरण महत्वपूर्ण नहीं हैं जब तक कि आप एक कंपाइलर इंजीनियर नहीं हैं।
मार्टिन यॉर्क

1
नीचे वोट दिया गया: ए) "स्कॉट मेयर्स", "एस मायर्स" नहीं; बी) असत्य उद्धरण: "प्रभावी सी ++": "आइटम 13: संदर्भ द्वारा अपवादों को पकड़ो "। यह अपवाद वस्तु के लिए जानकारी को जोड़ने / जोड़ने की अनुमति देगा।
सेबेस्टियन मच

3
@phresnel: आइटम 21 को न भूलें: "जब भी संभव हो तो कास्ट का उपयोग करें"। अपवाद के लिए कोई अच्छा मामला नहीं है। आपको "ए" फिक्सिंग और त्याग "होना चाहिए, बी) एक नया अपवाद पैदा करना या फिर से ग)।
मार्टिन यॉर्क

1
@phresnel: हां आपके पास आपके कारण हैं (अपने तर्क से सहमत न हों), मेरे पास मेरा है और हालांकि मैं इस विशिष्ट विषय के बारे में उनसे बात करने का दावा नहीं करूंगा या वास्तव में उनके दिमाग (मेयर्स, अलेक्जेंड्रेस्कु और सटर) को जानता हूं कि मुझे विश्वास है मेरी व्याख्या वैध है। लेकिन यदि आप सिएटल क्षेत्र में हैं, तो आप तीनों से बात कर सकते हैं क्योंकि वे नॉर्थ वेस्ट सी ++ यूजर ग्रुप में नियमित रूप से उपस्थित होते हैं (मेयर्स दूसरों की तुलना में कम अक्सर)।
मार्टिन यॉर्क

13

आप यहाँ विस्तृत विवरण के लिए एक नज़र डाल सकते हैं ।

यह सादे सी में उपयोग की जाने वाली चाल पर एक नज़र डालने में भी मदद कर सकता है ताकि कुछ बुनियादी प्रकार के अपवाद हैंडलिंग को लागू किया जा सके। यह निम्नलिखित तरीके से सेटजम्प () और लॉन्गजम्प () का उपयोग करता है: पूर्व अपवाद हैंडलर (जैसे "कैच") को चिह्नित करने के लिए स्टैक को बचाता है, जबकि बाद वाले का उपयोग "मान" करने के लिए किया जाता है। "फेंका गया" मान को ऐसे देखा जाता है जैसे कि उसे किसी फ़ंक्शन से लौटाया गया हो। "Try block" तब समाप्त होता है जब setjmp () को फिर से कॉल किया जाता है या जब फ़ंक्शन वापस आता है।


9

मुझे पता है कि यह एक पुराना सवाल है, लेकिन एक बहुत अच्छा एक्सपोज़र है, यहाँ gcc और VC में से प्रत्येक में प्रयुक्त दोनों तरीकों को समझाते हुए: http://www.hexblog.com/wp-content/uploads/2012/06/Recon- 2012 Skochinsky-संकलक-Internals.pdf

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