2012-11-04 3 views
51

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

मैंने पॉइंटर्स को हटाने के बारे में SO में कुछ प्रश्नों को देखा है, लेकिन वे सभी एक वर्ग को हटाने के लिए संबंधित हैं, न कि 'सरल' सूचक (या जो भी उचित शब्द हो), यहां कोड I 'चलाने का प्रयास हूँ:

#include <iostream>; 

using namespace std; 

int main() { 
    int myVar, 
     *myPointer; 

    myVar = 8; 
    myPointer = &myVar; 

    cout << "delete-ing pointers " << endl; 
    cout << "Memory address: " << myPointer << endl; 

    // Seems I can't *just* delete it, as it triggers an error 
    delete myPointer; 
    cout << "myPointer: " << myPointer << endl; 
    // Error: a.out(14399) malloc: *** error for object 0x7fff61e537f4: 
    // pointer being freed was not allocated 
    // *** set a breakpoint in malloc_error_break to debug 
    // Abort trap: 6 

    // Using the new keyword befor deleting it works, but 
    // does it really frees up the space? 
    myPointer = new int; 
    delete myPointer; 
    cout << "myPointer: " << myPointer << endl; 
    // myPointer continues to store a memory address. 

    // Using NULL before deleting it, seems to work. 
    myPointer = NULL; 
    delete myPointer; 
    cout << "myPointer: " << myPointer << endl; 
    // myPointer returns 0. 

} 

तो मेरी प्रश्न हैं:

  1. क्यों नहीं होगा पहला मामला काम करता है? एक सूचक का उपयोग करने और हटाने के लिए सबसे सरल उपयोग लगता है? त्रुटि कहती है कि स्मृति आवंटित नहीं की गई थी लेकिन 'कोउट' ने एक पता लौटाया।
  2. दूसरे उदाहरण पर त्रुटि ट्रिगर नहीं की जा रही है लेकिन मेरे पॉइंटर के मान का एक cout कर रहा है अभी भी मेमोरी पता देता है?
  3. क्या # 3 वास्तव में काम करता है? मुझे काम करने लगता है, सूचक अब एक पता संग्रह नहीं कर रहा है, क्या यह एक सूचक को हटाने का सही तरीका है?

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

+11

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

+0

हम्म ठीक है, मुझे यकीन नहीं है कि स्मार्ट पॉइंटर्स क्या हैं, लेकिन मैं इसे देख लूंगा, धन्यवाद! – leopic

+1

संक्षेप में, वे जो मैंने वर्णित किए हैं वे करते हैं। कुछ नया रखने के लिए, आप 'रीसेट' कहते हैं और यह पुराने को मुक्त करता है। प्रतिस्थापन के बिना इसे मुक्त करने के लिए, आप 'रिलीज' कहते हैं। जब यह गुंजाइश से बाहर हो जाता है, तो यह नष्ट हो जाता है, और यह किस प्रकार के आधार पर स्मृति को मुक्त कर सकता है। 'std :: unique_ptr' केवल एक मालिक के लिए है। 'std :: shared_ptr' इसे मुक्त करता है जब अंतिम मालिक संसाधन का मालिक बनता है। वे अपवाद भी सुरक्षित हैं। यदि आप एक के साथ संसाधन आवंटित करते हैं, और फिर अपवाद का सामना करते हैं, तो संसाधन ठीक से मुक्त हो जाएगा। – chris

उत्तर

106

myVar = 8; //not dynamically allocated. Can't call delete on it. 
myPointer = new int; //dynamically allocated, can call delete on it. 

पहले चर ढेर पर आवंटित किया गया था। आप new ऑपरेटर का उपयोग करके गतिशील रूप से (ढेर पर) आवंटित स्मृति पर केवल कॉल को कॉल कर सकते हैं।

3.

myPointer = NULL; 
    delete myPointer; 

ऊपर सभी पर कुछ नहीं किया। आपने कुछ भी मुक्त नहीं किया, क्योंकि पॉइंटर ने न्यूल पर इंगित किया था।


निम्नलिखित नहीं किया जाना चाहिए:

myPointer = new int; 
myPointer = NULL; //leaked memory, no pointer to above int 
delete myPointer; //no point at all 

आप शून्य पर यह इशारा किया, (नई int आप आवंटित) लीक स्मृति अकेली रह गई। आपको उस स्मृति को मुक्त करना चाहिए जिसे आप इंगित कर रहे थे। अब आवंटित new int तक पहुंचने का कोई तरीका नहीं है, इसलिए स्मृति रिसाव।


सही तरीका:

myPointer = new int; 
delete myPointer; //freed memory 
myPointer = NULL; //pointed dangling ptr to NULL 

बेहतर तरीका:

आप सी ++ का उपयोग कर रहे हैं, तो नहीं उपयोग कच्चे संकेत दिए गए है।smart pointers का उपयोग करें जो आपके लिए इन चीजों को थोड़ा ओवरहेड से संभाल सकता है। सी ++ 11 several के साथ आता है।

+9

"स्टैक पर" एक कार्यान्वयन विस्तार है - एक जिसे सी ++ स्पष्ट रूप से उल्लेख से बचाता है। अधिक सही शब्द "स्वचालित भंडारण अवधि के साथ" है। (सी ++ 11, 3.7.3) cHao

+4

धन्यवाद, मैं एक के लिए अपने जवाब चयनित) समझा क्या गलत था और ख) एक सबसे अच्छा अभ्यास है, बहुत दे रही है, धन्यवाद! – leopic

+0

मैं (Googlers की खातिर) जोड़ने के लिए, चाहे कितने भी पुराने इस पोस्ट है, 'myPointer' हटाना myPointer' deallocates' *, और 'myPointer' नहीं रह कुछ भी इशारा कर रही है चाहते हैं। यह दायरे के अंत में नष्ट हो जाएगा। – Tqn

7

वहाँ एक हटाना है हर नई के लिए, सी ++ में एक नियम है।

  1. क्यों नहीं होगा पहला मामला काम करता है? एक सूचक का उपयोग करने और हटाने के लिए सबसे सरल उपयोग लगता है? त्रुटि कहती है कि स्मृति आवंटित नहीं की गई थी लेकिन 'कोउट' ने एक पता लौटाया।

नया कभी नहीं कहा जाता है। तो पता है कि cout प्रिंट्स myVar के मेमोरी लोकेशन का पता है, या इस मामले में myPointer को आवंटित मान है। लेखन द्वारा:

myPointer = &myVar; 

आप कहते हैं:

myPointer = जहां myVar में डेटा संग्रहीत किया जाता है का पता

  1. पर दूसरा उदाहरण त्रुटि को ट्रिगर नहीं किया जा रहा है लेकिन myPointer के मान का एक cout अभी भी एक स्मृति पता देता है?

यह एक पता देता है जो हटाए गए स्मृति स्थान को इंगित करता है। क्योंकि पहले आप पॉइंटर बनाते हैं और अपना पॉइंट myPointer को असाइन करते हैं, दूसरा आप इसे हटा देते हैं, तीसरा आप इसे प्रिंट करते हैं। इसलिए जब तक आप मेरे पॉइंटर को कोई अन्य मान निर्दिष्ट नहीं करते हैं, हटाए गए पते बने रहेंगे।

  1. क्या # 3 वास्तव में काम करता है? मुझे काम करने लगता है, सूचक अब एक पता संग्रह नहीं कर रहा है, क्या यह एक सूचक को हटाने का सही तरीका है?

NULL 0 के बराबर है, तो आप 0 हटाते हैं, इसलिए आप कुछ भी नहीं हटाते हैं।

myPointer = NULL; 

जो बराबर है::

myPointer = 0; 
4
  1. आप एक चर ढेर पर आवंटित नष्ट करने के लिए कोशिश कर रहे हैं और यह तर्क है कि यह 0 प्रिंट क्योंकि तुमने किया है। आप यह नहीं कर सकते हैं
  2. पॉइंटर को हटाने से वास्तव में पॉइंटर को नष्ट नहीं किया जाता है, बस कब्जा कर लिया गया स्मृति ओएस को दिया जाता है। जब तक स्मृति किसी दूसरे चर के लिए उपयोग नहीं की जाती है, या अन्यथा छेड़छाड़ की जाती है तब तक आप इसका उपयोग कर सकते हैं। इसलिए हटाने के बाद न्यूल (0) में पॉइंटर सेट करना अच्छा अभ्यास है।
  3. एक पूर्ण सूचक को हटाने से कुछ भी हट नहीं जाता है।
10

पॉइंटर्स सामान्य चर के समान हैं जिसमें आपको उन्हें हटाने की आवश्यकता नहीं है। फ़ंक्शन निष्पादन और/या प्रोग्राम के अंत के अंत में उन्हें स्मृति से निकाल दिया जाता है।

आप फिर भी इस तरह उदाहरण के लिए एक स्मृति के 'ब्लॉक' आवंटित करने के लिए, संकेत का उपयोग कर सकते हैं:

int *some_integers = new int[20000] 

यह 20000 पूर्णांकों के लिए स्मृति स्थान आवंटित करेगा। उपयोगी, क्योंकि स्टैक का सीमित आकार होता है और आप स्टैक ओवरफ़्लो त्रुटि के बिना 'इनट्स' के बड़े लोड के साथ गड़बड़ करना चाहते हैं।

जब भी आप नए कॉल करते हैं, तो आपको अपने प्रोग्राम के अंत में 'हटाएं' चाहिए, क्योंकि अन्यथा आपको मेमोरी लीक मिल जाएगी, और कुछ आवंटित मेमोरी स्पेस का उपयोग अन्य प्रोग्रामों के लिए कभी नहीं किया जाएगा। ऐसा करने के लिए:

delete [] some_integers; 

आशा है कि मदद करता है।

+1

मैं सिर्फ यह जोड़ना चाहता हूं कि आवंटित स्मृति अन्य प्रोग्रामों के उपयोग के लिए वापस कर दी जाएगी, लेकिन केवल आपके प्रोग्राम के निष्पादन के बाद ही समाप्त हो जाएगा। – sk4l

1
int value, *ptr; 

value = 8; 
ptr = &value; 
// ptr points to value, which lives on a stack frame. 
// you are not responsible for managing its lifetime. 

ptr = new int; 
delete ptr; 
// yes this is the normal way to manage the lifetime of 
// dynamically allocated memory, you new'ed it, you delete it. 

ptr = nullptr; 
delete ptr; 
// this is illogical, essentially you are saying delete nothing. 
+1

इसके अलावा, स्टैक फ्रेम पर इस व्याख्यान को देखें http://www.youtube.com/watch?v=bjObm0hxIYY, और पॉइंटर्स पर http://www.youtube.com/watch?v=Rxvv9krECNw। –

12

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

कल्पना कीजिए:

int *ptr = new int; 
// ptr has the address of the memory. 
// at this point, the actual memory doesn't have anything. 
*ptr = 8; 
// you're assigning the integer 8 into that memory. 
delete ptr; 
// you are only deleting the memory. 
// at this point the pointer still has the same memory address (as you could 
// notice from your 2nd test) but what inside that memory is gone! 

जब आप किया

ptr = NULL; 
// you didn't delete the memory 
// you're only saying that this pointer is now pointing to "nowhere". 
// the memory that was pointed by this pointer is now lost. 

सी ++ कि आप delete के लिए सूचक है कि null के लिए अंक की कोशिश लेकिन यह वास्तव में कुछ भी नहीं है, बस नहीं देता है की अनुमति देता है कोई त्रुटि

+1

धन्यवाद, यह बहुत उपयोगी था, मैंने सोचा कि मुझे सभी पॉइंटर्स को हटाना है, यह नहीं पता था कि केवल उन लोगों के लिए था जो नए थे, धन्यवाद। – leopic