दिलचस्प पोस्ट
सी प्रोग्राम में सीरियल टर्मिनल पर बाइनरी डेटा कैसे पढ़ा जाए? क्यों नकारात्मक वजन किनारों के लिए Dijkstra के एल्गोरिदम काम नहीं करता है? एक बैश स्क्रिप्ट का उपयोग करके डुप्लिकेट प्रविष्टियों को निकालें एक श्रेणी के भीतर एक निष्पक्ष यादृच्छिक पूर्णांक उत्पन्न करने के लिए इष्टतम एल्गोरिथ्म क्या है? Android बंद पृष्ठभूमि संगीत एक ईवेंट हैंडलर को रोकने के लिए सी # पैटर्न दो बार दोगुना क्या मैं नोडजेएस (ईएस 7) में वादा कर सकता हूं और भूल सकता हूं? कैसे jquery / javascript के माध्यम से <head> में कुछ भी जोड़ने के लिए? मैं अपने ब्राउज़र में ज्यूपिटर / आईप्याथॉन नोटबुक की सेल की चौड़ाई कैसे बढ़ाऊं? Google कोड से एसवीएन / कछुआ का उपयोग कर मैं कोड कैसे डाउनलोड करूं? मैं Node.js का उपयोग कर "मॉड्यूल नहीं पा सकता" त्रुटि कैसे हल कर सकता हूँ? IPhones फोटो लाइब्रेरी में कस्टम एल्बम में फोटो सहेजें ब्लॉब से अर्रेबफर तक कैसे जाना है मैं जावा में पॉइंटर्स का उपयोग कैसे कर सकता हूं? CSS3 में अवरोही ढाल प्रभाव

सी ++ में अपवाद कैसे काम करते हैं (पर्दे के पीछे)

मैं लोगों को देख रहा हूं कि अपवाद धीमे हैं लेकिन मैं कभी भी कोई सबूत नहीं देखता हूं। इसलिए पूछने के बजाय कि वे क्या हैं, मैं पूछूंगा कि अपवाद इस दृश्य के पीछे कैसे काम करते हैं, इसलिए मैं इसका उपयोग करने के लिए निर्णय ले सकता हूं और यदि वे धीमे हैं

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

अपवाद वास्तव में कैसे काम करते हैं?

Solutions Collecting From Web of "सी ++ में अपवाद कैसे काम करते हैं (पर्दे के पीछे)"

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

class MyException { public: MyException() { } ~MyException() { } }; void my_throwing_function(bool throwit) { if (throwit) throw MyException(); } void another_function(); void log(unsigned count); void my_catching_function() { log(0); try { log(1); another_function(); log(2); } catch (const MyException& e) { log(3); } log(4); } 

मैंने इसे g++ -m32 -W -Wall -O3 -save-temps -c साथ संकलित किया, और जन असेंबली फ़ाइल को देखा

  .file "foo.cpp" .section .text._ZN11MyExceptionD1Ev,"axG",@progbits,_ZN11MyExceptionD1Ev,comdat .align 2 .p2align 4,,15 .weak _ZN11MyExceptionD1Ev .type _ZN11MyExceptionD1Ev, @function _ZN11MyExceptionD1Ev: .LFB7: pushl %ebp .LCFI0: movl %esp, %ebp .LCFI1: popl %ebp ret .LFE7: .size _ZN11MyExceptionD1Ev, .-_ZN11MyExceptionD1Ev 

_ZN11MyExceptionD1Ev MyException::~MyException() , इसलिए संकलक ने यह निर्णय लिया कि विनाशक की एक गैर-इनलाइन कॉपी की आवश्यकता है।

 .globl __gxx_personality_v0 .globl _Unwind_Resume .text .align 2 .p2align 4,,15 .globl _Z20my_catching_functionv .type _Z20my_catching_functionv, @function _Z20my_catching_functionv: .LFB9: pushl %ebp .LCFI2: movl %esp, %ebp .LCFI3: pushl %ebx .LCFI4: subl $20, %esp .LCFI5: movl $0, (%esp) .LEHB0: call _Z3logj .LEHE0: movl $1, (%esp) .LEHB1: call _Z3logj call _Z16another_functionv movl $2, (%esp) call _Z3logj .LEHE1: .L5: movl $4, (%esp) .LEHB2: call _Z3logj addl $20, %esp popl %ebx popl %ebp ret .L12: subl $1, %edx movl %eax, %ebx je .L16 .L14: movl %ebx, (%esp) call _Unwind_Resume .LEHE2: .L16: .L6: movl %eax, (%esp) call __cxa_begin_catch movl $3, (%esp) .LEHB3: call _Z3logj .LEHE3: call __cxa_end_catch .p2align 4,,3 jmp .L5 .L11: .L8: movl %eax, %ebx .p2align 4,,6 call __cxa_end_catch .p2align 4,,6 jmp .L14 .LFE9: .size _Z20my_catching_functionv, .-_Z20my_catching_functionv .section .gcc_except_table,"a",@progbits .align 4 .LLSDA9: .byte 0xff .byte 0x0 .uleb128 .LLSDATT9-.LLSDATTD9 .LLSDATTD9: .byte 0x1 .uleb128 .LLSDACSE9-.LLSDACSB9 .LLSDACSB9: .uleb128 .LEHB0-.LFB9 .uleb128 .LEHE0-.LEHB0 .uleb128 0x0 .uleb128 0x0 .uleb128 .LEHB1-.LFB9 .uleb128 .LEHE1-.LEHB1 .uleb128 .L12-.LFB9 .uleb128 0x1 .uleb128 .LEHB2-.LFB9 .uleb128 .LEHE2-.LEHB2 .uleb128 0x0 .uleb128 0x0 .uleb128 .LEHB3-.LFB9 .uleb128 .LEHE3-.LEHB3 .uleb128 .L11-.LFB9 .uleb128 0x0 .LLSDACSE9: .byte 0x1 .byte 0x0 .align 4 .long _ZTI11MyException .LLSDATT9: 

आश्चर्य! सामान्य कोड पथ पर कोई अतिरिक्त निर्देश नहीं हैं I इसके बजाय कंपाइलर ने अतिरिक्त आउट-ऑफ-लाइन फिक्सअप कोड ब्लॉकों का निर्माण किया, फ़ंक्शन के अंत में एक तालिका के माध्यम से संदर्भित (जो वास्तव में निष्पादन योग्य के एक अलग खंड पर लगाया गया है)। इन तालिकाओं ( _ZTI11MyException पर आधारित है typeinfo for MyException ) के आधार पर मानक लाइब्रेरी द्वारा सभी काम किया जाता है

ठीक है, यह वास्तव में मेरे लिए आश्चर्यचकित नहीं था, मैं पहले से ही जानता था कि यह संकलक कैसे किया। विधानसभा उत्पादन के साथ जारी:

  .text .align 2 .p2align 4,,15 .globl _Z20my_throwing_functionb .type _Z20my_throwing_functionb, @function _Z20my_throwing_functionb: .LFB8: pushl %ebp .LCFI6: movl %esp, %ebp .LCFI7: subl $24, %esp .LCFI8: cmpb $0, 8(%ebp) jne .L21 leave ret .L21: movl $1, (%esp) call __cxa_allocate_exception movl $_ZN11MyExceptionD1Ev, 8(%esp) movl $_ZTI11MyException, 4(%esp) movl %eax, (%esp) call __cxa_throw .LFE8: .size _Z20my_throwing_functionb, .-_Z20my_throwing_functionb 

यहां हम अपवाद फेंकने के लिए कोड देखते हैं। हालांकि कोई अतिरिक्त उपरि नहीं था, क्योंकि एक अपवाद फेंका जा सकता है, वास्तव में एक अपवाद को फेंकने और पकड़ने में बहुत अधिक उपरि है। इसमें से अधिकांश __cxa_throw अंदर छिपे हुए हैं, जो कि:

  • अपवाद तालिकाओं की मदद से स्टैक पर चलें जब तक कि उस अपवाद के लिए कोई हेन्डलर नहीं मिल जाता।
  • ढेर को खोलें, जब तक कि उस हैंडलर को नहीं मिलती।
  • वास्तव में हेन्डलर को कॉल करें

केवल एक मूल्य लौटने की लागत के साथ तुलना करें, और आप देखेंगे कि अपवाद केवल असाधारण रिटर्न के लिए क्यों उपयोग किया जाना चाहिए।

समाप्त करने के लिए, बाकी असेंबली फ़ाइल:

  .weak _ZTI11MyException .section .rodata._ZTI11MyException,"aG",@progbits,_ZTI11MyException,comdat .align 4 .type _ZTI11MyException, @object .size _ZTI11MyException, 8 _ZTI11MyException: .long _ZTVN10__cxxabiv117__class_type_infoE+8 .long _ZTS11MyException .weak _ZTS11MyException .section .rodata._ZTS11MyException,"aG",@progbits,_ZTS11MyException,comdat .type _ZTS11MyException, @object .size _ZTS11MyException, 14 _ZTS11MyException: .string "11MyException" 

टाइपइन्फो डेटा

  .section .eh_frame,"a",@progbits .Lframe1: .long .LECIE1-.LSCIE1 .LSCIE1: .long 0x0 .byte 0x1 .string "zPL" .uleb128 0x1 .sleb128 -4 .byte 0x8 .uleb128 0x6 .byte 0x0 .long __gxx_personality_v0 .byte 0x0 .byte 0xc .uleb128 0x4 .uleb128 0x4 .byte 0x88 .uleb128 0x1 .align 4 .LECIE1: .LSFDE3: .long .LEFDE3-.LASFDE3 .LASFDE3: .long .LASFDE3-.Lframe1 .long .LFB9 .long .LFE9-.LFB9 .uleb128 0x4 .long .LLSDA9 .byte 0x4 .long .LCFI2-.LFB9 .byte 0xe .uleb128 0x8 .byte 0x85 .uleb128 0x2 .byte 0x4 .long .LCFI3-.LCFI2 .byte 0xd .uleb128 0x5 .byte 0x4 .long .LCFI5-.LCFI3 .byte 0x83 .uleb128 0x3 .align 4 .LEFDE3: .LSFDE5: .long .LEFDE5-.LASFDE5 .LASFDE5: .long .LASFDE5-.Lframe1 .long .LFB8 .long .LFE8-.LFB8 .uleb128 0x4 .long 0x0 .byte 0x4 .long .LCFI6-.LFB8 .byte 0xe .uleb128 0x8 .byte 0x85 .uleb128 0x2 .byte 0x4 .long .LCFI7-.LCFI6 .byte 0xd .uleb128 0x5 .align 4 .LEFDE5: .ident "GCC: (GNU) 4.1.2 (Ubuntu 4.1.2-0ubuntu4)" .section .note.GNU-stack,"",@progbits 

इससे भी अधिक अपवाद हैंडलिंग टेबल, और मिश्रित अतिरिक्त जानकारी।

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

यदि आप अधिक जानकारी चाहते हैं, तो विशेष रूप से सभी __cxa_ कार्य करता है, मूल विवरण देखें, जो वे से आए हैं:

  • इटेनियम सी ++ एबीआई

पुराने दिनों में धीमी गति से अपवाद सही था
अधिकांश आधुनिक कंपाइलर में अब यह सच नहीं है।

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

अपवाद हैंडलिंग कोड की लागत जब कोई अपवाद नहीं किया जा रहा है, तो वास्तव में शून्य है।

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

इसके अलावा वहाँ novices के लिए एक gotcha है:
हालांकि अपवाद ऑब्जेक्ट छोटे होने वाले हैं, लेकिन कुछ लोगों ने बहुत सी चीजों को उनके अंदर रखा। उसके बाद आपके पास अपवाद ऑब्जेक्ट को कॉपी करने की कीमत है समाधान दो गुना है:

  • अपने अपवाद में अतिरिक्त सामान मत डालें
  • Const संदर्भ से पकड़ो।

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

आप अपवाद को कार्यान्वित कर सकते हैं कई तरीके हैं, लेकिन आम तौर पर वे ओएस से कुछ अंतर्निहित समर्थन पर भरोसा करेंगे। विंडोज़ पर यह संरचित अपवाद प्रहस्तन तंत्र है।

कोड प्रोजेक्ट पर विवरण की अच्छी चर्चा है: सी ++ कंपाइलर अपवाद हैंडलिंग कैसे लागू करता है

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

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

मैट पिरेक ने Win32 स्ट्रक्चर्ड अपवाद हैंडलिंग पर एक उत्कृष्ट लेख लिखा है। हालांकि यह लेख मूलतः 1 99 7 में लिखा गया था, यह आज भी लागू होता है (लेकिन निश्चित रूप से केवल विंडोज पर लागू होता है)

यह लेख इस समस्या की जांच करता है और मूल रूप से पाता है कि व्यवहार में अपवादों के लिए एक रन-टाइम लागत होती है, हालांकि अपवाद नहीं फेंक दिया जाता है, तो लागत काफी कम है। अच्छा लेख, अनुशंसित

मेरे एक दोस्त ने थोड़ा सा लिखा कि कैसे कुछ साल पहले विज़ुअल सी ++ अपवादों को अपवाद करता है

http://www.xyzw.de/c160.html

सभी अच्छे उत्तर

साथ ही, इस बारे में सोचें कि कोड को डिबग करना कितना आसान है जो कोड को अपवाद छोड़ने की अनुमति देने के बजाय 'अगर चेक' को फाटक के रूप में तरीके के शीर्ष पर देता है

मेरा आदर्श वाक्य है कि कोड लिखना आसान है जो काम करता है सबसे महत्वपूर्ण बात यह है कि उस व्यक्ति के लिए कोड लिखना जो इसे देखता है। कुछ मामलों में, यह आप 9 महीनों में है, और आप अपना नाम दुर्व्यवहार नहीं करना चाहते हैं!