2015-11-30 11 views
17

निम्न उदाहरण पर विचार करें:vtable के लिए विनाशक से सुरक्षित अपवाद फेंक रहा है?

#include <csignal> 

class A 
{ 
public: 
    virtual ~A() {} 
    virtual void foo() = 0; 
}; 

class B : public A 
{ 
public: 
    virtual ~B() { throw 5; } 
    virtual void foo() {} 
}; 

int main(int, char * []) 
{ 
    A * b = new B(); 

    try 
    { 
     delete b; 
    } 
    catch (...) 
    { 
     raise(SIGTRAP); 
    } 
    return 0; 
} 

मैं हमेशा सोचा है (अनुभवहीन मुझे) है कि जब कार्यक्रम catch अनुभाग में, इस मामले में हो जाता है, तो B वस्तु, जिस पर b अंक वैसे ही रहेंगे यह काफी है, क्योंकि तार्किक है कि अपवादकर्ता को "रद्द" (अगर सुरक्षित रूप से प्रोग्राम किया गया) विनाशक के प्रभाव होगा। लेकिन जब मैं gdb में इस स्निपेट भागने की कोशिश की और catch खंड में ब्रेकप्वाइंट को मिला मैंने देखा कि बी वस्तु चला गया था और केवल एक आधार वस्तु छोड़ दिया क्योंकि vtable इस तरह देखा:

(gdb) i vtbl b 
vtable for 'A' @ 0x400cf0 (subobject @ 0x603010): 
[0]: 0x0 
[1]: 0x0 
[2]: 0x4008e0 <[email protected]> 

मेरा प्रश्न: अगर मैं जुनून से विनाशक से अपवाद फेंकना चाहता हूं तो vtable से बचने के लिए कोई रास्ता है?

+6

विनाशक फेंकने अजीब हैं, यदि संभव हो तो इससे बचें। –

+0

विनाशकों को फेंकना अजीब से भी बदतर है। वे वास्तव में [काफी खतरनाक] हैं (https://isocpp.org/wiki/faq/exceptions#dtors-shouldnt-throw) और लगभग सभी स्थितियों में से बचा जाना चाहिए। – Kevin

+0

आप किसी ऑब्जेक्ट के विनाश को क्यों रोकना चाहते हैं? क्या आप जानते हैं कि एक गुंजाइश का मतलब है, स्थानीय वस्तुओं का विनाश? तो क्या आप चाहते हैं कि कंपाइलर आपकी ऑब्जेक्ट को नष्ट करने से बचने के लिए स्टैक को ऊपर उठाए? क्या आपने कभी देखा है, संसाधनों की सफाई के लिए कार्य, आमतौर पर हमेशा सफल होते हैं - और शून्य वापस आते हैं। –

उत्तर

17

मैंने हमेशा सोचा है (मुझे बेवकूफ़ बनाओ) कि जब इस मामले में प्रोग्राम कैच सेक्शन में हो जाता है, तो ऑब्जेक्ट बी पर बी बी बिंदु बरकरार रहेगा क्योंकि यह काफी तार्किक है कि अपवाद "रद्द" होगा (अगर सुरक्षित रूप से प्रोग्राम किया गया) विनाशक का प्रभाव।

यह सच नहीं है। मानक का कहना है:

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

(N4140 में 15,2/2)

और, शायद अधिक महत्वपूर्ण बात:

प्रकार टी का एक उद्देश्य के जीवनकाल समाप्त होता है जब:

- अगर टी एक वर्ग है एक गैर-तुच्छ विनाशक (12.4) के साथ टाइप करें, विनाशक कॉल

(3.41/1.3 एन 4140 में)

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

इसके पीछे तर्कसंगत शायद "आधा विनाशकारी" वस्तुओं को मना कर रहा है, क्योंकि यह स्पष्ट नहीं है कि किसी वस्तु की स्थिति जिसे नष्ट नहीं किया जा सकता है। उदाहरण के लिए, क्या होगा यदि केवल कुछ सदस्यों को नष्ट कर दिया जाए?

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

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

तो निष्कर्ष में:

वहाँ एक रास्ता से बचने के लिए है (आधा -) vtable के विनाश अगर मैं जुनून से एक विनाशक से अपवाद फेंकना चाहता हूँ?

नहीं जैसे ही आप विनाशक में प्रवेश करते हैं, आपकी वस्तु के लिए किया जाता है।

6

जब कार्यक्रम पकड़ अनुभाग में, इस मामले में हो जाता है, तो बी, क्योंकि यह काफी तार्किक है कि अपवाद "रद्द" (अगर सुरक्षित रूप से प्रोग्राम किया) होगा प्रभाव है, जिस पर ख अंक वैसे ही रहेंगे आपत्ति विनाशक का।

सं। lifetime of an object ends when its destructor starts

आप विनाशक को रद्द नहीं कर सकते हैं।

जैसा कि अन्य ने कहा, सी ++ में विनाशकों को फेंकना अजीब है और आप उन्हें except for special cases से बचना चाहते हैं।

+0

ऐसा लगता है कि मेरे पास एक विशेष मामला है। मेरे असली कार्यक्रम में बी ऑब्जेक्ट एक वी 4 एल 2 फ्रेम रैपर है और इसके विनाशक में मैं इसे वापस ड्राइवर के कतार में करने का प्रयास करता हूं और यदि विफल रहता है तो मुझे अगले प्रयास तक रैपर को नष्ट करने की उम्मीद है। – krokoziabla

+0

@krokoziabla: उस मामले में, मैं सुझाव दूंगा कि आपको जो चाहिए वह एक रैपर है जो ब्याज की वस्तु के लिए सूचक होता है और जो सीधे वस्तुओं को साफ करने के बजाय, पॉइंटर को सफाई की प्रतीक्षा करने वाली वस्तुओं की कतार में ले जाता है। कतार में ऑब्जेक्ट्स को उस संदर्भ में संसाधित किया जा सकता है जो इस प्रकार फेंकने वाले अपवादों से निपटने में सक्षम होगा। सी ++ सभी के लिए आवश्यक है कि प्रकारों को इस तरह से परिभाषित किया जाए कि विनाशक संभवतः असफल नहीं हो सकते हैं, लेकिन यदि विनाशक वास्तव में सफाई करने के लिए ज़िम्मेदार नहीं है, लेकिन केवल इसे करने के लिए व्यवस्था करने के लिए ... – supercat

+0

... तो निर्माता की क्षमता अपने दायित्वों को पूरा करने के लिए वास्तव में आवश्यक सफाई करने की वस्तु की क्षमता पर निर्भर नहीं होगा। – supercat

0

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

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

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

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