2010-07-05 10 views
40

मुझे पता है कि मेरे विनाशकों को ढेर के सामान्य खोलने पर कहा जाता है और जब अपवाद फेंक दिया जाता है, लेकिन बाहर निकलने पर नहीं कहा जाता है।सी ++ विनाशकों को किस परिस्थिति में नहीं बुलाया जा रहा है?

क्या कोई अन्य मामले हैं जहां मेरे विनाशकों को बुलाया नहीं जा रहा है? SIGINT या SIGSEGV जैसे सिग्नल के बारे में क्या? मुझे लगता है कि एसआईजीएसईजीवी के लिए, उन्हें बुलाया नहीं जाता है, लेकिन साइनइन के लिए वे हैं, मुझे कैसे पता चलेगा कि कौन से सिग्नल ढेर को खोलेंगे?

क्या कोई अन्य परिस्थितियां हैं जहां उन्हें नहीं बुलाया जाएगा?

+12

के रूप में यहां बताया, http://thedailywtf.com/Articles/My-Tales.aspx, आप भी पता होना चाहिए नाशक जब बुलाया नहीं की जाएगी पावर प्लग खींचा गया है;)। –

+4

SIGINT स्टैक को अनदेखा नहीं करेगा जबतक कि आप एक सिग्नल हैंडलर स्थापित नहीं करते जो डिफ़ॉल्ट व्यवहार को ओवरराइड करता है। डिफ़ॉल्ट रूप से SIGINT परिणाम तत्काल कार्यक्रम समाप्ति में परिणाम। – karunski

+0

इसे उत्तर के रूप में पोस्ट नहीं किया जा रहा है क्योंकि यह प्रश्न में एक निरीक्षण की तरह लगता है। स्थिर, स्वचालित या थ्रेड स्टोरेज अवधि वाले ऑब्जेक्ट्स के जीवनकाल के अंत में विनाशकों को स्वचालित रूप से (सामान्य परिस्थितियों में) कहा जाता है। ** डायनामिक ** स्टोरेज अवधि के साथ ऑब्जेक्ट के लिए विनाशक को केवल तभी बुलाया जाता है जब ऑब्जेक्ट पर पॉइंटर पर 'डिलीट' कहा जाता है। इसलिए एक विनाशक को गतिशील वस्तुओं के लिए बुलाया नहीं जा रहा है जिसके लिए 'हटाना' कभी नहीं कहा जाता है (चाहे क्योंकि स्मृति रिसाव असंभव हो या निरीक्षण के द्वारा)। –

उत्तर

45

क्या कोई अन्य परिस्थितियां हैं जहां वे [विनाशक] नहीं कहेंगे?

  1. लांग कूदता है: इन प्रक्रिया तनाव मुक्त प्राकृतिक ढेर के साथ हस्तक्षेप और अक्सर सी में अपरिभाषित व्यवहार हो ++।
  2. समय से पहले बाहर निकलता है (यदि आप पहले से ही इन ने कहा, हालांकि यह ध्यान देने योग्य बात है कि फेंकने जबकि पहले से ही तनाव मुक्त होने के ढेर के रूप में एक अपवाद का एक परिणाम के फेंके जाने अपरिभाषित व्यवहार करने के लिए सुराग के लायक है और यही कारण है कि हम dtors से बाहर कभी नहीं फेंक चाहिए)
  3. फेंक एक कन्स्ट्रक्टर से कक्षा के लिए dtor आह्वान नहीं करता है। यही कारण है कि, यदि आप एक सीटीआर में कई अलग-अलग पॉइंटर्स (और स्मार्ट पॉइंटर्स नहीं) द्वारा प्रबंधित कई मेमोरी ब्लॉक आवंटित करते हैं, तो आपको फ़ंक्शन-स्तरीय प्रयास ब्लॉक का उपयोग करने या प्रारंभकर्ता सूची का उपयोग करने से बचने की आवश्यकता है और ctor में एक कोशिश/पकड़ ब्लॉक है शरीर (या बेहतर अभी तक, केवल scoped_ptr जैसे स्मार्ट पॉइंटर का उपयोग करें क्योंकि प्रारंभकर्ता सूची में अब तक किसी भी सदस्य को सफलतापूर्वक प्रारंभ किया गया है, भले ही कक्षा डीटीआर नहीं कहा जाएगा)।
  4. जैसा कि इंगित किया गया है, एक आधार पॉइंटर के माध्यम से एक वर्ग हटाए जाने पर एक डॉट वर्चुअल बनाने में असफल हो सकता है, सबक्लास डॉटर्स (अपरिभाषित व्यवहार) का आह्वान करने में विफल हो सकता है।
  5. ऑपरेटर के लिए मिलान करने वाले ऑपरेटर को हटाने/हटाने [] को कॉल करने में विफल [नया कॉल] (अपरिभाषित व्यवहार - dtor को आमंत्रित करने में असफल हो सकता है)।
  6. deallocate अनुभाग में एक कस्टम मेमोरी आवंटक के साथ प्लेसमेंट नया उपयोग करते समय मैन्युअल रूप से dtor को आवेदक करने में विफल।
  7. memcpy जैसे कार्यों का उपयोग करना जो प्रतिलिपि ctors का आह्वान किए बिना केवल एक मेमोरी ब्लॉक को कॉपी करता है। mem * फ़ंक्शन सी ++ में घातक हैं क्योंकि वे कक्षा के निजी डेटा पर बुलडोज़ करते हैं, vtables को ओवरराइट करते हैं, आदि परिणाम आमतौर पर अपरिभाषित व्यवहार होता है।
  8. एक अधूरी प्रकार पर स्मार्ट संकेत (auto_ptr) में से कुछ के आरंभ होने, इस discussion
+4

अच्छी सूची है, लेकिन बिंदु 3 में कोई दोष है: आप वास्तव में प्रारंभकर्ता सूची के चारों ओर एक ब्लॉक ब्लॉक कर सकते हैं, कार्य स्तर को देखने का प्रयास करें ब्लॉक: 'स्ट्रक्चर एक्स {एक्स() कोशिश करें: x_ (42) {} पकड़ें (। ..) {} निजी: int x_; }; वास्तव में आप इसे किसी भी फ़ंक्शन के लिए उपयोग कर सकते हैं जैसे 'void foo() try {} catch (...) {} 'लेकिन कुछ महत्वपूर्ण कंपाइलर्स (VS2008, यह नहीं जानते कि यह बाद के संस्करणों में तय है या नहीं) यह। स्मार्ट पॉइंटर्स के बारे में सलाह हालांकि वैध है। –

+0

@ फैबियो धन्यवाद फैबियो, मैं इसे इंगित करूंगा! मुझे इन फ़ंक्शन-स्तरीय प्रयास/पकड़ ब्लॉक के बारे में पता नहीं था (केवल हर जगह आरएआईआई का उपयोग करना पसंद करते हैं क्योंकि यह सिरदर्द से राहत देता है)। – stinky472

+0

सामान्य रूप से, एक अच्छी सूची। हालांकि, # 4, और # 5 तकनीकी रूप से अपरिभाषित व्यवहार हैं, इसलिए मानक के बारे में कुछ भी कहना नहीं है कि विनाशकों को बुलाया जाता है या नहीं। जैसा कि आप कहते हैं (या सिर्फ क्रैश हो सकता है) अधिकांश कंपेलर व्यवहार करेंगे। – KeithB

2

abort मानक या स्थिर स्टोरेज अवधि की वस्तुओं के लिए विनाशकों को निष्पादित किए बिना प्रोग्राम को समाप्त करता है। अन्य परिस्थितियों के लिए आपको कार्यान्वयन विशिष्ट दस्तावेज़ों को पढ़ना चाहिए।

3

ही द्वारा एक सिग्नल , वर्तमान धागा और इसलिए विनाशकर्ता के आह्वान के निष्पादन को प्रभावित नहीं करेगा क्योंकि यह अपने आप ही ढेर, जहाँ आपके वस्तुओं मौजूद नहीं है के साथ एक अलग निष्पादन संदर्भ है। यह एक बाधा की तरह है: इसे आपके निष्पादन संदर्भ के बाहर कहीं भी संभाला जाता है, और यदि संभाला जाता है, तो नियंत्रण आपके प्रोग्राम में वापस कर दिया जाता है।

मल्टीथ्रेडिंग के साथ ही, सी ++ भाषा सिग्नल की धारणा नहीं जानता है। ये दोनों एक दूसरे के लिए पूरी तरह से ऑर्थोगोनल हैं और दो असंबंधित मानकों द्वारा निर्दिष्ट हैं। वे कैसे इंटरैक्ट करते हैं, कार्यान्वयन तक है, जब तक यह मानकों में से किसी एक को तोड़ता नहीं है।

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

7

सी ++ मानक कैसे विशिष्ट संकेत नियंत्रित किया जाना चाहिए के बारे में कुछ भी नहीं कहना है - कई कार्यान्वयन SIGINT समर्थन नहीं कर सकते, आदि Destructors अगर exit() या abort() या terminate() कहा जाता है कहा जाता है नहीं किया जाएगा।

संपादित करें: मैं सिर्फ सी ++ मानक के माध्यम से एक त्वरित खोज किया है और मैं कुछ भी बताता है कि कैसे संकेत वस्तु जीवन काल के साथ बातचीत नहीं मिल सकता है - शायद मुझे की तुलना में बेहतर मानकों फू के साथ किसी ने कुछ मिल सकता है?

आगे संपादित करें: एक और सवाल का जवाब है, मैं इस मानक में पाया: एक दायरे से

बाहर निकलने पर (हालांकि पूरा किया), विनाशकर्ता (12.4) हैं सभी का निर्माण वस्तुओं के लिए बुलाया स्वचालित भंडारण अवधि (3.7.2) (नामित वस्तुओं या अस्थायी) जो उस दायरे में घोषित हैं, में उनके घोषणा के विपरीत क्रम के साथ।

तो ऐसा लगता है कि एक संकेत की प्राप्ति पर विनाशकों को बुलाया जाना चाहिए।

+0

सिग्नल की प्राप्ति पर, प्रोग्राम नियंत्रण गुंजाइश से बाहर नहीं निकलता है। तो उद्धृत मानक लागू नहीं होता है। POSIX सिग्नल हैंडलर का डिफ़ॉल्ट व्यवहार किसी भी स्टैक को अनचाहे या विनाश नहीं करता है। – karunski

+1

@karunski अगर सिग्नल हैंडलर स्थापित है तो यह निश्चित रूप से दायरे से बाहर निकलता है। –

+0

@Neil Butterworth निश्चित रूप से, लेकिन यह डिफ़ॉल्ट रूप से नहीं होता है। अधिक सही निष्कर्ष होगा "सिग्नल हैंडल (प्राप्त नहीं किया गया) के बाद विनाशकों को बुलाया जाना चाहिए और उस बिंदु पर नियंत्रण रिटर्न जहां सिग्नल हैंडलर का आह्वान किया गया था" – karunski

1

मूल रूप से दो स्थितियां हैं, जहां विनाशकों को बुलाया जाता है: फ़ंक्शन (या अपवादों पर) के अंत में अवांछित स्टैक पर, यदि कोई (या संदर्भ काउंटर) कॉल हटा देता है।

एक विशेष स्थिति स्थिर वस्तुओं में पाया जा सकता है - वे at_exit के माध्यम से कार्यक्रम के अंत में विलुप्त कर रहे हैं, लेकिन यह अभी भी 2 स्थिति है।

कौन सा संकेत at_exit माध्यम से जा रहा निर्भर हो सकता है छोड़ देता है, को मारने -9 प्रक्रिया तुरंत मार डालेगा, अन्य संकेतों यह बाहर निकलने के लिए बता देंगे लेकिन कैसे वास्तव में संकेत कॉलबैक पर निर्भर है।

3

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

+1

इस मामले में, आपको अपरिभाषित व्यवहार मिलेगा। –

2

एक समारोह तो देख सकते हैं या विधि एक विनिर्देश फेंकता है, और फेंकता कुछ विनिर्देश द्वारा कवर नहीं, डिफ़ॉल्ट व्यवहार करने के लिए है तुरंत बाहर निकलें। ढेर अवांछित नहीं है और विनाशकों को बुलाया नहीं जाता है।

POSIX संकेत एक ऑपरेटिंग सिस्टम विशिष्ट निर्माण कर रहे हैं और सी ++ वस्तु गुंजाइश का बोध भी नहीं की है। आम तौर पर आप सिग्नल के साथ कुछ भी नहीं कर सकते हैं, सिवाय इसके कि, इसे फँसें, ग्लोबल फ्लैग वैरिएबल सेट करें, और उसके बाद सिग्नल हैंडलर निकलने के बाद इसे बाद में अपने सी ++ कोड में संभाल लें। जीसीसी के

हाल संस्करणों आप तुल्यकालिक संकेत संचालकों के भीतर से एक अपवाद है, जो उम्मीद तनाव मुक्त और विनाश की प्रक्रिया में परिणाम है फेंकने के लिए अनुमति देते हैं। यह बहुत ऑपरेटिंग सिस्टम और संकलक विशिष्ट है, हालांकि

2

यहाँ लेकिन अभी भी अधूरा जवाब का एक बहुत!

मुझे एक और मामला मिला जहां विनाशकों को निष्पादित नहीं किया गया। ऐसा तब होता है जब अपवाद को पुस्तकालय सीमा में पकड़ा जाता है।

यहां और विवरण देखें:

Destructors not executed (no stack unwinding) when exception is thrown

+0

यह एक बग की तरह लगता है कि मुझे संदेह है कि सी ++ विनिर्देश इस तरह के व्यवहार के लिए अनुमति देता है। – WilliamKF

+0

यहां सवाल यह है: "किस परिस्थितियों में विनाशकों को बुलाया नहीं जाता है"। भले ही यह विजुअल स्टूडियो में एक बग है, यह सवाल का एक वैध जवाब है, क्योंकि एक बग भी एक परिधि है। लोग यहां Google से आते हैं और उनमें से कुछ को यह बताने के बिना ही यह विशिष्ट समस्या का अनुभव हो सकता है कि यह बग है या नहीं। – Elmue

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