2009-01-15 75 views
28

आज, मैंने कुछ विरासत कोड देखा है। विनाशक में एक बयान है जैसे "delete this"। मुझे लगता है, यह कॉल रिकर्सिव होगा। यह क्यों काम कर रहा है?"इसे हटाएं" का उपयोग क्या है?

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

क्या ऐसे वक्तव्यों का उपयोग करने के लिए कोई अन्य स्थितियां हैं?

उत्तर

32

"इसे हटाएं" आमतौर पर रेफ गिने गए ऑब्जेक्ट्स के लिए उपयोग किया जाता है। एक रेफरी ऑब्जेक्ट के लिए जब डिलीट करने का निर्णय आमतौर पर ऑब्जेक्ट पर रखा जाता है। यहां एक उदाहरण दिया गया है कि रिलीज विधि कैसा दिखाई देगी [1]।

int MyRefCountedObject::Release() { 
    _refCount--; 
    if (0 == _refCount) { 
    delete this; 
    return 0; 
    } 
    return _refCount; 
} 

एटीएल COM ऑब्जेक्ट्स इस पैटर्न का एक प्रमुख उदाहरण हैं।

[1] हां मुझे एहसास है कि यह धागा सुरक्षित नहीं है।

+0

जबकि refcounted वस्तुओं का आत्म-विलोपन एक बहुत ही आम पैटर्न है, मुझे लगता है कि मूल प्रश्न इसे एक विनाशक में डालने के बारे में था, रिलीज() फ़ंक्शन नहीं, जिस स्थिति में यह केवल पागल है। – rmeador

+0

@ रेमेडोर, वास्तव में दो प्रश्न हैं। शीर्षक और अंतिम वाक्य दोनों सुझाव देते हैं कि "इसे हटाएं" के वैध उपयोगों को जानना चाहते हैं। मुझे उम्मीद है कि मैंने इसका उत्तर दिया। मध्य एक प्रश्न का सुझाव देता है "इसे एक डॉटर में क्यों हटाएं"। मैं ऐसा करने के लिए सहमत हूं कि पागल हो रहा है। – JaredPar

+10

आपके नमूना कोड में एक बग है। यदि _refCount सदस्य चर है, तो जब आप "इसे हटा दें" तो सदस्य चर अब मौजूद नहीं है, इसलिए आपकी "वापसी _refCount" पंक्ति में व्यवहार को अपरिभाषित किया गया है। – ChrisN

24

delete this एक विनाशक में मान्य नहीं है। इसका इस्तेमाल कहीं और किया जा सकता है। लेकिन यह शायद ही कभी एक अच्छा विचार है। wxWidgets ढांचा इसे अपने धागे वर्ग के लिए उपयोग करता है। इसमें एक मोड है, जहां थ्रेड निष्पादन समाप्त होता है, यह स्वचालित रूप से सिस्टम संसाधनों और स्वयं (wxThread ऑब्जेक्ट) को मुक्त करता है। मैंने इसे बहुत परेशान पाया, क्योंकि बाहर से, आप नहीं जानते कि यह संदर्भित करने के लिए मान्य है या नहीं - आप IsValid जैसे फ़ंक्शन को कॉल नहीं कर सकते हैं, क्योंकि ऑब्जेक्ट मौजूद नहीं है। यह delete this के साथ मुख्य समस्या की तरह गंध करता है, समस्या के अलावा कि इसका उपयोग गैर गतिशील वस्तुओं के लिए नहीं किया जा सकता है।

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

C++ FAQ इसके बारे में एक प्रविष्टि है। ऊपर मेरे दावे पर सी ++ स्टैंडर्ड बोली (3.8p5):

एक वस्तु के जीवनकाल से पहले शुरू कर दिया है लेकिन भंडारण जो वस्तु पर कब्जा आवंटित होगा किया गया है या, के बाद एक वस्तु का जीवन समाप्त हो गया है और इससे पहले कि के बाद भंडारण जिस पर कब्जा किया गया ऑब्जेक्ट पुन: उपयोग या जारी किया जाता है, कोई भी सूचक जो भंडारण स्थान को संदर्भित करता है जहां ऑब्जेक्ट होगा या स्थित था, लेकिन केवल सीमित तरीकों से उपयोग किया जा सकता है। [...] यदि ऑब्जेक्ट एक गैर-तुच्छ विनाशक के साथ कक्षा प्रकार का होगा या पॉइंटर का उपयोग हटाए जाने वाले अभिव्यक्ति के संचालन के रूप में किया जाता है, तो प्रोग्राम ने व्यवहार को अपरिभाषित किया है।

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

3

जहां शुरुआती सी ++ दिनों में ऐसा करने के अच्छे कारण माना जाता है। उदाहरण के लिए एक रेफ गिनती ऑब्जेक्ट का स्वयं हटाना (जैसा कि जेरेडपायर कहते हैं)। जहां तक ​​मुझे पता है कि वे लंबे समय तक सभी को एक बुरा विचार माना गया है।

+0

बिल्कुल मुझे क्या लगता है। आज अगर मुझे एक रेफरी ऑब्जेक्ट लिखना होगा, तो मैं डेटा को एक अतिरिक्त ऑब्जेक्ट में रखूंगा, और मेजबान ऑब्जेक्ट (जिसे कॉपी किया गया है) को लपेटा गया डेटा हटाएं जब संदर्भ गणना शून्य पर गिर जाती है। स्वयं को हटाने की गंध :) –

+0

@ जोहान्स शैब - litb: पूरी तरह से सहमत हैं; एक वस्तु जो उसकी जिम्मेदारियों के लिए ज़िम्मेदार है और खुद को साफ करने का निर्णय लेती है? Yucky! – jason

+1

@ जोहान्सचैब-लीटब तो मेजबान ऑब्जेक्ट को इसके बदले में स्वयं को हटा देना होगा ... –

2

एक दोगुनी-लिंक्ड सूची में, किसी भी बाहरी संरचना, जैसे उच्च स्तरीय "सूची" ऑब्जेक्ट को संदर्भित किए बिना नोड को निकालना संभव है। यह प्रत्येक नोड को अपने स्वयं के डीलोकेशन को संभालने के लिए उचित बनाता है (संभावित रूप से स्मृति के उसी पूल से प्रारंभिक आवंटन को संभालने के लिए एक पूरक स्थिर विधि के साथ मिलकर)। इस स्थिति में, यह नोड ऑब्जेक्ट को स्वयं हटाने के लिए समझ सकता है (जब उपयोगकर्ता द्वारा अनुरोध किया जाता है)।

void RemoveAndDeallocate() 
{ 
    LinkedListNode *current_prev = prev, *current_next = next; 
    current_prev->next = current_next; 
    current_next->prev = current_prev; 
    delete this; 
} 

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

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