2009-11-24 26 views
20

मैं कोड के टुकड़े पर काम कर रहा था और मुझे संदेह से हमला किया गया था: अगर मैं उस सूचक को न्यूल आवंटित करता हूं तो पॉइंटर को आवंटित स्मृति का क्या होता है?नल पॉइंटर इसे हटाने के समान है?

उदाहरण के लिए:

A = new MyClass(); 

{...do something in the meantime...} 

A = NULL; 

अंतरिक्ष अभी भी आवंटित किया जाता है, लेकिन वहाँ यह करने के लिए कोई संदर्भ नहीं है। क्या वह जगह बाद में मुक्त हो जाएगी, क्या इसका पुन: उपयोग किया जाएगा, क्या यह ढेर पर रहेगा, या क्या?

+11

कोई विचार नहीं कि यह क्यों कम किया गया था। यह पूरी तरह से शब्द नहीं है, लेकिन निश्चित रूप से एक वैध जवाब है। मेरी इच्छा है कि इस तरह के संदेहों से अधिक नए लोगों पर हमला किया गया और उन्होंने इस तरह के दोषों के साथ कोड छोड़ दिया। – sharptooth

+4

@ शार्पतोथ: सहमत हुए। यह हमारे लिए गहराई से पुराने सी/सी ++ देवों के लिए एक साधारण सवाल प्रतीत हो सकता है, लेकिन प्रोग्रामिंग के लिए नए, या गैर-जीसी भाषाओं के लिए यह एक बिल्कुल वैध सवाल है। – philsquared

+2

"... यह ढेर पर रहेगा ...": नया ढेर पर स्मृति आवंटित नहीं करता है। आपका पॉइंटर ढेर पर है, लेकिन ऑब्जेक्ट स्वयं नहीं है। यह ढेर पर आवंटित किया जाता है। – Lucas

उत्तर

5
A = new MyClass(); 

{...do something in the meantime...} 

A = NULL; 

जिस तरह से मैं इसका ट्रैक रखता हूं वह यह है कि दो अलग-अलग वस्तुएं हैं। ढेर पर कहीं, MyClass उदाहरण new द्वारा आवंटित किया गया है। और ढेर पर, A नामक एक सूचक है।

A सिर्फ एक सूचक है, बाहर जादुई कुछ भी नहीं है, और इसमें ढेर-आवंटित MyClass ऑब्जेक्ट के लिए कुछ विशेष कनेक्शन नहीं है। यह अभी उस बिंदु को इंगित करता है, लेकिन यह बदल सकता है।

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

10

यह एक स्मृति रिसाव है। आपको मैन्युअल रूप से आवंटित स्मृति को हटाना होगा।

5

आप delete A;

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

+0

ए मुक्त ए को हटाएं; – Naveen

+0

मॉलोक के साथ मुफ्त, नए के साथ हटाएं का उपयोग करें। इन्हें मिश्रण न करें। – philsquared

+0

यह एक गलती थी। –

3

अधिकांश आधुनिक ओएस पर, एप्लिकेशन की स्मृति को एप्लिकेशन से बाहर निकलने पर पुनः दावा किया जाएगा। इस बीच, आपके पास मेमोरी रिसाव है।

2

नहीं, यह हमेशा प्रक्रिया के लिए खो जाएगा। आपके पास मेमोरी रिसाव होगा। यदि आप ऐसा करते रहें, तो आपका प्रोग्राम अंततः स्मृति से बाहर हो जाएगा !! इससे बचने के लिए, delete ऑब्जेक्ट जब आपको इसकी आवश्यकता नहीं है।

अक्सर लोग इसे हटाने के बाद पॉइंटर को NULL पर सेट करेंगे, ताकि प्रोग्राम के अन्य भाग सत्यापित कर सकें कि ऑब्जेक्ट हटा दिया गया है, और इस प्रकार इसे फिर से एक्सेस करने या हटाने से बचें।

+0

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

32

यह एक क्लासिक रिसाव है। जैसा कि आप कहते हैं, स्मृति आवंटित बनी हुई है लेकिन कुछ भी इसका संदर्भ नहीं दे रहा है, इसलिए इसे तब तक पुनः दावा नहीं किया जा सकता है जब तक कि प्रक्रिया समाप्त न हो जाए।

स्मृति नष्ट साथ पुनः आवंटित की जाती किया जाना चाहिए -। लेकिन एक स्मार्ट सूचक का उपयोग कर (जैसे std :: auto_ptr या बढ़ावा देने :: shared_ptr (या tr1 :: shared_ptr) रैप करने के लिए सूचक संकेत के साथ काम करने का एक ज्यादा सुरक्षित तरीका है

का तरीका यहां बताया एसटीडी का उपयोग कर अपने उदाहरण पुनर्लेखन सकता है :: auto_ptr:

std::auto_ptr a(new MyClass()); 

/*...do something in the meantime...*/ 

a.reset(); 

+3

यदि आप केवल एक पॉइंटर आवंटित कर रहे हैं जिसे आप दायरे के अंत तक जीवित रखना चाहते हैं, तो 'scoped_ptr' एक बेहतर विकल्प है। – Pieter

+1

@Pieter, सहमत हुए। तर्कसंगत रूप से उस मामले में std :: auto_ptr लगभग उतना ही अच्छा है, लेकिन यदि आप पहले से ऐसा नहीं कर चुके हैं तो बूस्ट लाने की आवश्यकता नहीं है - हालांकि यदि आपके पास TR1 है तो आप इसे वहां से भी प्राप्त कर सकते हैं – philsquared

3

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

उम्मीद है कि यह मदद करता है, सर्वश्रेष्ठ संबंध, टॉम।

2

सी ++ शामिल नहीं है कचरा कलेक्टर है, जैसे कुछ अन्य भाषाएं हैं (जावा, सी #, ...) ताकि आप allocaled हटाना होगा अपने आप वस्तुओं।

25

ज्यादातर परिस्थितियों में, इससे आपकी प्रक्रिया में स्मृति रिसाव हो जाएगी। आपके पास C++ में स्मृति प्रबंधन के लिए कई विकल्प हैं।

  1. जब आप इसके साथ काम करते हैं तो मैन्युअल रूप से मुक्त स्मृति के लिए delete का उपयोग करें। यह सही हो सकता है, विशेष रूप से अपवाद हैंडलिंग के संदर्भ में।

  2. आप (auto_ptr, shared_ptr, unique_ptr, आदि)

  3. सी ++ एक कचरा कलेक्टर साथ नहीं आता है, लेकिन कुछ भी आप एक (जैसे Boehm GC का उपयोग करने से रोकता है के लिए स्मृति प्रबंधन के लिए एक स्मार्ट सूचक का प्रयोग करें) यदि आप उस मार्ग पर जाना चाहते हैं।

+0

यह उत्तर अधिक उल्टा होना चाहिए । +1 इंगित करने के लिए कि आप स्मार्ट पॉइंटर्स को इंगित करने के लिए सी ++ – philsquared

+2

+1 के साथ तीसरे पक्ष के कचरा कलेक्टरों का उपयोग कर सकते हैं। – Sebastian

0

पॉइंटर पर NULL असाइन करके आप आवंटित स्मृति मुक्त नहीं करेंगे। आपको आवंटित स्मृति मुक्त करने के लिए डेलोकेशन फ़ंक्शन को कॉल करना चाहिए। सी ++ मानक 5.3.4/8 के अनुसार: "यदि आवंटित प्रकार एक गैर-सरणी प्रकार है, आवंटन फ़ंक्शन का नाम operator new है और डेलोकेशन फ़ंक्शन का नाम operator delete है"। मैं निम्नलिखित समारोह का सुझाव सकता है सुरक्षित रूप से संकेत (उन्हें NULL बताए के साथ) को हटाने के लिए: ढेर पर संग्रहीत

template<typename T> 
inline void SafeDelete(T*& p) 
{ 
    // Check whether type is complete. 
    // Deleting incomplete type will lead to undefined behavior 
    // according to C++ Standard 5.3.5/5. 
    typedef char type_must_be_complete[ sizeof(T)? 1: -1 ]; 
    (void) sizeof(type_must_be_complete); 

    delete p; 
    p = NULL; 
} 
+0

हटाएं और हटाएं [] के बीच भेद का उल्लेख करने के लिए अच्छा बिंदु, लेकिन मुझे लगता है कि शेष प्रश्न के संदर्भ में चीजों को कम कर रहा है। – philsquared

+1

यदि मैं शुरुआती था तो मुझे केवल "जटिल" चीजों के बारे में पता था ... :) –

+0

तो, यह डेलोकेशन सुरक्षा के कुछ मुद्दों को संभालता है, लेकिन 'हटाएं/हटाएं [] 'को संभालने के लिए कोई चाल है भेद? मैं अपने सिर के ऊपर से एक को नहीं समझ सकता, लेकिन सी ++ में बहुत सारे गहरे जादू उपलब्ध हैं – Novelocrat

1

चर, प्रत्येक कार्य करता है, उदा की स्थानीय चर रहे हैं int बड़ा [10]; ढेर पर संग्रहीत चर, वे वैरिएबल हैं जिन्हें आपने मॉलोक(), कॉलोक(), नया() इत्यादि जैसे स्पष्ट मेमोरी आवंटन दिनचर्या का उपयोग करके शुरू किया है।

स्टैक पर संग्रहीत चर के जीवनकाल में बराबर है वर्तमान ढेर फ्रेम का जीवनकाल। अंग्रेजी में, जब फ़ंक्शन वापस आता है, तो आप अब यह नहीं मान सकते कि वेरिएबल उन चीज़ों को पकड़ते हैं जिन्हें आप पकड़ते हैं। यही कारण है कि यह एक वैरिएबल वापस करने के लिए एक क्लासिक गलती है जिसे एक समारोह में स्थानीय घोषित किया गया था।

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