2012-01-11 9 views
10

निम्नलिखित कोड पर विचार करें'इसे हटाएं;' कथन के दौरान क्या हो रहा है? निम्नलिखित दो विकल्पों में</p> <pre><code>class foo { public: foo(){} ~foo(){} void done() { delete this;} private: int x; }; </code></pre> <p>क्या हो रहा है (और यह वैध है?):

विकल्प 1:

void main() 
{ 
    foo* a = new foo(); 
    a->done(); 
    delete a; 
} 

विकल्प 2:

void main() 
{ 
    foo a; 
    a.done(); 
} 

दूसरा delete a; कथन चुनने पर कथन होगा आयन 1 अपवाद या ढेर भ्रष्टाचार का कारण बन जाएगा?

विकल्प 2 अपवाद या ढेर भ्रष्टाचार का कारण बन जाएगा?

+0

क्या आप गलती से कक्षा के लिए शुरुआती ब्रैकेट भूल गए थे या क्या यह वास्तव में प्रतिलिपि कोड कॉपी है? – Neophile

+0

@Nerds: एक टाइपो - निश्चित ... – NirMH

+0

दिलचस्प। मुझे लगता है कि पहले सेगफॉल्ट या हीप भ्रष्टाचार का कारण बनता है, और दूसरा जो कुछ भी स्टैक करने के लिए पॉइंटर को हटा देता है। – cha0site

उत्तर

19

delete this; की अनुमति है, यह ऑब्जेक्ट हटा देता है।

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

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

+0

और उम्मीद है कि यह पूर्व होगा। – Xeo

+1

अपरिभाषित व्यवहार, सर्वोत्तम और सही उत्तर। +1 –

4

दोनों एक त्रुटि का कारण बनेंगे।

पहले सूचक त्रुटि पैदा जबकि दूसरा एक ढेर पर आवंटित किया जाता है दूसरा delete साथ दो बार नष्ट कर दिया जाता है, और परोक्ष हटाया नहीं जा सकता (त्रुटि नाशक के पहले मंगलाचरण के कारण)।

+0

आपने मुझे इसे हराया! – Neophile

+0

मैंने सवाल संपादित किया। मुझे लगता है कि इसे ढेर पर आवंटित किया जाना चाहिए और फिर 'किया' के साथ हटा दिया जाना चाहिए। इस मामले में क्या हो रहा है? ढेर पर हटना समझ में नहीं आता है और शायद ओपी द्वारा नहीं पूछा जा रहा है। – duedl0r

+0

आपका उत्तर सही है, लेकिन सवाल यह था कि त्रुटि का * क्रम * क्या होगा। – cha0site

1

दोनों एक त्रुटि का कारण होता है, क्या आप चाहते हैं:

void main() 
{ 
    foo* a = new foo(); 
    a->done(); 
} 

कौन सा संकलक नीचे की तरह कुछ, मुझे आशा है कि जो "इस" थोड़ा कम भ्रामक को हटाने बनाता है करने के लिए विस्तार होगा।

void __foo_done(foo* this) 
{ 
    delete this; 
} 

void main() 
{ 
    foo* a = new foo(); 
    __foo_done(a); 
} 

भी देखें, Is it legal (and moral) for a member function to say delete this?

+0

क्या होगा यदि यह किसी मानक-लेआउट (या पीओडी) वर्ग में ऑब्जेक्ट का पहला सदस्य है, जिसे सादे नए के साथ आवंटित किया गया था, और इसमें कोई अन्य विनाशक नहीं है? (ऐसा नहीं है कि यह _insane_ नहीं होगा, लेकिन, अच्छी तरह से ...) – Random832

+0

@ Random832: मैं आपके प्रश्न का एहसास नहीं कर सकता, क्षमा करें। – ronag

+0

आपके द्वारा लिंक किए गए अक्सर पूछे जाने वाले प्रश्न की शर्तों की एक सूची प्रदान करता है जिसके तहत 'इसे हटाएं' सुरक्षित है। चूंकि मानक-लेआउट वर्ग के पहले सदस्य के पास मूल ऑब्जेक्ट के समान पता है, ऐसा लगता है कि सैद्धांतिक रूप से एक और मामला होगा। – Random832

1

delete this कॉलिंग एक बुरा विचार है। जो भी new पर कॉल करता है उसे delete पर कॉल करना चाहिए। इसलिए अन्य प्रतिक्रियाओं में हाइलाइट की गई समस्याएं।

ऑब्जेक्ट्स की सरणी को समझते समय भी आप मेमोरी लीक/अपरिभाषित व्यवहार कर सकते हैं।

+0

क्यों 'इसे हटाएं' एक बुरा विचार बुला रहा है? मैं कहूंगा कि कई (अधिकांश?) अनुप्रयोगों में, यह 'हटाएं' का सबसे आम रूप होगा। –

+0

@JamesKanze क्यों? 'इसे हटाएं' वस्तुओं को जारी करने के सामान्य तरीके नहीं हैं। –

+0

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

0

दोनों मामलों में आपका ढेर दूषित हो जाएगा। बेशक, आप विकल्प 2 "->" में उपयोग नहीं कर सकते हैं यदि बाएं मान (इस मामले में, "ए") एक सूचक नहीं है, विकल्प 2 में सही रूप a.done() होगा; लेकिन हाँ, अगर आप 1 को हटाने की कोशिश करते हैं तो आपको ढेर भ्रष्टाचार होना चाहिए 1) पहले से हटा दिया गया है, या 2) स्थानीय चर।

कॉलिंग "इसे हटाएं" तकनीकी रूप से मान्य है और स्मृति को मुक्त करता है।

संपादित मैं उत्सुक था और वास्तव में इस की कोशिश की:

class foo 
{ 
public: 
    foo(){} 
    ~foo(){} 
    void done() { delete this; } 
    void test() { x = 2; } 
    int getx() { return x; } 
private: 
    int x; 
} ; 


int main(int argc, char* argv[]) 
{ 
    foo *a = new foo(); 
    a->done(); 
    a->test(); 
    int x = a->getx(); 
    printf("%i\n", x); 
    return x; 
} 

printf को एक कॉल सफल होगा, और x मूल्य 2 का आयोजन करेगा।

+0

धन्यवाद - वास्तव में विकल्प 2 में "->" उपयोग बाहरी संपादन द्वारा किया गया एक टाइपो था - मैंने फिर से प्रश्न अपडेट किया है। – NirMH

+0

तो, 'इसे हटाएं' ऑब्जेक्ट मेमोरी को ढेर से छोड़ देगा? – NirMH

+0

@NirMH: "->" उपयोग आपके द्वारा लिखा गया था। – duedl0r

0

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

3

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

यह सुनिश्चित करता है कि केवल वर्ग ही खुद को हटा सके।

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

+0

बेशक यह सभी त्रुटियों को रोकता नहीं है उदा। ऑब्जेक्ट का उपयोग करके() पर कॉल करने के बाद ऑब्जेक्ट का उपयोग करना (यहां तक ​​कि कॉल किया गया() फिर भी एक डबल डिलीट का आह्वान करेगा)। – CashCow

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