2010-06-17 13 views
16

कल्पना कीजिए मैं एक वर्ग है कि (अब के लिए स्मार्ट संकेत के बारे में भूल) स्मृति आवंटित करता है: नाशक में वस्तुओं को हटाने के साथ हीक्या यह एक विनाशक में न्यूल को पॉइंटर्स सेट करने लायक है?

class Foo 
{ 
public: 
    Foo() : bar(new Bar) 
    { 
    } 

    ~Foo() 
    { 
    delete bar; 
    } 

    void doSomething() 
    { 
    bar->doSomething(); 
    } 

private: 
    Bar* bar; 
}; 

यह भी उन्हें स्थापित करने को शून्य पर लायक है?

मुझे लगता है कि ऊपर दिए गए उदाहरण के विनाशक में पॉइंटर को न्यूल में सेट करना समय की बर्बादी है।

+0

संभवतः आपके पास कोई 'getBar() 'विधि नहीं है ... – Skilldrick

+5

एक बेहतर सवाल यह है कि आपके कोड में कच्चा सूचक क्यों है। – GManNickG

+5

अधिक महत्वपूर्ण; जब आपकी कक्षा आवंटित स्मृति से संबंधित होती है तो एक आकलन ऑपरेटर और एक कॉपी-कन्स्ट्रक्टर प्रदान करें। –

उत्तर

27

के बाद से नाशक आखिरी बात यह है कि एक वस्तु पर कहा जाता है इससे पहले कि यह "मर जाता है," मैं कहूंगा कि NULL करने के लिए इसे बाद में स्थापित करने के लिए कोई जरूरत नहीं है।

किसी अन्य मामले में, मैं हमेशा एक सूचक NULL के लिए उस पर delete बुला के बाद निर्धारित किया है।

0

नहीं, यह इसके लायक नहीं है।

लेकिन यदि आप लगातार बने रहना चाहते हैं तो आपको शायद यह करना चाहिए।

मुझे क्या आम तौर पर होता है एक नि: शुल्क समारोह है कि मैं हर बार जब मैं आवंटित डेटा (घटना अधिक नि: शुल्क कार्यों यदि आवश्यक) रिक्त करने की आवश्यकता का उपयोग कर सकते बनाने के लिए है। उन कार्यों में आपको पॉइंटर्स को न्यूल (या अमान्य मान के पहचानकर्ता) पर सेट करने की सलाह दी जाती है।

2

वास्तव में डिबगिंग कारणों के लिए इसके लायक हो सकता है। हालांकि यह जब वर्ग के लिए निरीक्षण से संकेत मिलता है कि क्या एक संसाधन सही ढंग से मुक्त कर दिया गया है या नहीं डिबगिंग के दौरान एक आसान सहायता हो सकता है -

+1

क्या आपके कंपाइलर पैटर्न-भरने वाले सामान डीबग मोड में विनाश पर नहीं हैं? – avakar

+0

फिर भी, आपको एक डबल विनाश पर संदेह हो सकता है, और यह देखना चाहते हैं कि इस विशिष्ट विनाशक ने निष्पादित किया है या नहीं। –

+0

पॉइंटर को न तो डबल डिलीट किए गए ऑब्जेक्ट में डबल डिलीट किए गए ऑब्जेक्ट में दुर्घटना हो जाएगी, उन्हें बाहर छुपाएं समस्या – paulm

1

आम तौर पर, नहीं, स्पष्ट रूप से उन्हें नाशक में हटाने के बाद NULL की ओर इशारा स्थापित करने के लिए कोई जरूरत नहीं है।

एक आम मुहावरा एक SAFE_DELETE मैक्रो, जो सूचक को हटा देता है और आप के लिए यह NULL सेट घोषित करने के लिए है:

#define SAFE_DELETE(x) delete (x); x = NULL 

SAFE_DELETE(bar) 

इस मामलों में जहां सूचक बाद में पुन: उपयोग किया जा सकता है में विशेष रूप से उपयोगी है।

+0

हमारे पास पहले से ही मैक्रो है और यह हर जगह विनाशकों में उपयोग किया जाता है जो मुझे लगता है कि शायद अधिक है। – Rob

+0

* विनाशक * में हटाकर, कन्स्ट्रक्टर नहीं :) –

+0

ओह। मैं गलती से तुम्हारी वस्तु। फिक्स्ड। एक असुरक्षित मैक्रो के लिए –

-1

हमेशा उन्हें हटाने के बाद पॉइंटर्स को न्यूल पर सेट करना अच्छा अभ्यास है। इसके अलावा कुछ कोड जांच उपकरण इसे लागू करते हैं।

+4

यह एक खराब प्रथा है, यह डबल डिलीट बग छुपाता है। –

+5

विनाशक * में * * * हटाने के बाद * के बीच एक महत्वपूर्ण अंतर है। – peterchen

0

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

इसके अलावा पॉइंटर की जांच करने के लिए उपयोगी है, इसका उपयोग करने से पहले मान्य है।

if (NULL == pSomething) 
{ 
    // Safe to operate on pSomething 
} 
else 
{ 
    // Not safe to operate on pSomething 
} 

शून्य शून्य करने के लिए indavertently की स्थापना pSomething के खिलाफ अगर हालत गार्ड में पहली लाना जब आप पर्ची और दूसरा '=' बाहर याद आती है। आपको एक बग के बजाय संकलन त्रुटि मिलती है जो ट्रैक करने में समय लगता है।

+1

आप कहां जा रहे हैं कि यह सूचक न्यूल है या नहीं? वस्तु नष्ट होने के बाद, इसके सदस्य अब मौजूद नहीं हैं। आप अब उनके साथ कुछ भी नहीं कर सकते हैं, यहां तक ​​कि यह भी जांच न करें कि वे नल हैं या नहीं।पॉइंटर स्वयं मौजूद होने पर आपको केवल पॉइंटर को न्यूल पर सेट करना चाहिए, लेकिन ऑब्जेक्ट की ओर इशारा नहीं करना चाहिए। – MSalters

3

सबसे पहले, यह एक सी अभ्यास है, और एक विवादित है। कुछ तर्क देते हैं कि (सी के लिए) कि यह बग को छुपाता है जो जल्द ही सतह पर उपयोग नहीं किया जाता है, और इसे आवंटित नहीं किया गया था, जिसे किसी आवंटित स्मृति भाग के उपयोग से अलग करना असंभव है ...

अब सी ++?यह बेकार है, लेकिन सी

सी में की तुलना में एक ही कारण के लिए नहीं ++ यह delete उपयोग करने के लिए एक बग है। यदि आप स्मार्ट पॉइंटर्स का उपयोग करना चाहते थे, तो आप इसके बारे में चिंतित नहीं होंगे, और आप लीकिंग का जोखिम नहीं उठाएंगे (यानी: क्या आप सुनिश्चित हैं कि आपकी प्रतिलिपि निर्माता और असाइनमेंट ऑपरेटर अपवाद सुरक्षित है? थ्रेड सुरक्षित?)

अंत में, एक में विनाशक यह वास्तव में पूरी तरह से बेकार है ... विनाशक चलाने के बाद किसी ऑब्जेक्ट के किसी भी क्षेत्र तक पहुंचने के लिए अपरिभाषित व्यवहार है। आपने मेमोरी जारी कर दी है, इसलिए वहां सावधानीपूर्वक रखे गए नल को ओवरराइट करने के लिए वहां कुछ और लिखा जा सकता है। और वास्तव में, जिस तरह मेमोरी आवंटकों का काम होता है, वह अक्सर ताजा रूप से हटाए गए जोनों को पुन: आवंटित करने के लिए होता है: यह कैशिंग प्रदर्शन को बढ़ाता है ... और यह भी ट्रूअर (हाहा!) है अगर हम ढेर के बारे में बात कर रहे हैं।

मेरे राय: SAFE_DELETE आसन्न कयामत का एक संकेत है।

5

आप दो कारणों के लिए, नहीं करना चाहिए:

  • यह डिबगिंग एड्स, लेकिन आधुनिक वातावरण में, नष्ट कर दिया वस्तुओं आमतौर पर डिबग बनाता में पहचानने योग्य बिट पैटर्न के साथ पहले से ही ओवरराइट कर रहे हैं।

  • एक बड़े आवेदन में, यह शट डाउन प्रदर्शन को काफी हद तक खराब कर सकता है। सबसे बुरी स्थिति परिदृश्य में, आपके ऐप को बंद करना मतलब है कि दर्जनों अलग-अलग विनाशकों को बुलाएं, और सैकड़ों ढेर पृष्ठों को लिखना जो वर्तमान में डिस्क पर बदल गए हैं।

+0

हटाए गए ऑब्जेक्ट्स आमतौर पर DEBUG बिल्ड में ओवरराइट किए जाते हैं। नष्ट वस्तुओं को हालांकि नहीं, इसलिए डीटीआर में ज्ञात-बुरे पते को स्थापित करने से बहुत सारी समझ हो सकती है। (पॉइंटर न्यूल सेट करना संदिग्ध है हालांकि माइकल बोर ने समझाया - और मैं पूरी तरह से उससे सहमत हूं।) –

1

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

30

कई उत्तरों का उल्लेख है कि डिबगिंग में सहायता के लिए डेबग बिल्ड में ऐसा करना उचित हो सकता है।

इस मत करो।

आप संभावित रूप से एक डिबग बिल्ड में किसी समस्या को छिपाने में मदद करेंगे जो आपके रिलीज में छिपा हुआ नहीं है, जिससे आप वास्तव में ग्राहकों को देते हैं (जो आपके डीबग बिल्ड के विपरीत प्रभाव है)।

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

कहो कि doSomething() की तरह देखा:

void doSomething() 
{ 
    if (bar) bar->doSomething(); 
} 

फिर bar शून्य करने के लिए सिर्फ एक बग को छिपाने अगर वहाँ एक नष्ट कर दिया Foo उद्देश्य यह है कि Foo::doSomething() कहा जाता है के लिए एक झूलने संदर्भ था मदद की है की स्थापना।

यदि आपका सूचक साफ अप की तरह देखा:

~Foo() 
{ 
    delete bar; 
    if (DEBUG) bar = (bar_type*)(long_ptr)(0xDEADBEEF); 
} 

आप (हालांकि अभी bar अकेला छोड़ने शायद ऐसा ही प्रभाव होता है) बग को पकड़ने का एक बेहतर मौका हो सकता है।

अब अगर कुछ भी Foo उद्देश्य यह है कि हटाई गई सामग्री के लिए एक झूलने संदर्भ है, bar के किसी भी उपयोग यह एक शून्य की जांच की वजह से संदर्भित से बचने नहीं होगा - यह खुशी से सूचक का उपयोग करने की कोशिश करेंगे और आप एक दुर्घटना मिलेगा कि आप डिबग बिल्ड में कुछ भी खराब होने के बजाय ठीक कर सकते हैं, लेकिन आपके ग्राहक के रिलीज बिल्ड में अभी भी लटकने वाले संदर्भ (बीमार प्रभाव के लिए) उपयोग किया जा रहा है।

जब आप डीबग मोड में संकलित कर रहे हैं, तो संभावना बहुत अच्छी है कि डीबग हीप मैनेजर पहले से ही आपके लिए यह कर रहा है (कम से कम एमएसवीसी के डीबग रनटाइम हीप मैनेजर स्मृति को इंगित करने के लिए 0xDD के साथ मुक्त स्मृति को ओवरराइट करेगा मृत/मुक्त कर दिया)।

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

यह नियम अन्य कच्चे पॉइंटर्स पर भी लागू हो सकता है, लेकिन यह इस बात पर निर्भर करता है कि पॉइंटर का उपयोग कैसे किया जाता है।

+0

मैं इस उत्तर से 100% सहमत हूं। –

+3

अकेले 'बार' छोड़ने से हटाए जाने के बाद एक्सेस छुपा सकते हैं। इसे न्यूल पर सेट करना डबल डिलीट छुपा सकता है। इसे 'डेडबीफ' पर सेट करना एक उत्कृष्ट विचार है। –

1

मैं, उदाहरण के साथ और स्मार्ट बिंदु जहां यह स्पष्ट रूप से शून्य पर स्थापित करने के बिना सभी कीमत पर कच्चे संकेत से बचने के उपयोगी साबित होगा,:

के साथ:

class foo 
{ 
    public: 
     foo() : m_something(new int) { } 

     void doStuff() 
     { 
      // delete + new again - for whatever reason this might need doing 
      m_something.reset(new int); 
     } 

    private: 
     std::unique_ptr<int> m_something; // int as an example, no need for it to be on the heap in "real" code 
} 

के बिना:

class foo 
{ 
    public: 
    foo() : m_something(new int) { } 
    ~foo() 
    { 
     delete m_something; 
    } 

    void doStuff() 
    { 
     delete m_something; 

     // Without this, if the next line throws then the dtor will do a double delete 
     m_something = nullptr; 

     m_something = new int; 
    } 

    private: 
    int* m_something 
} 
संबंधित मुद्दे