C ++ में एक सूचक को हटाना


92

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

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

#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. पहला मामला क्यों नहीं चलेगा? एक पॉइंटर का उपयोग और हटाने के लिए सबसे सीधा उपयोग लगता है? त्रुटि कहती है कि मेमोरी आवंटित नहीं की गई थी लेकिन 'cout' ने एक पता लौटा दिया।
  2. दूसरे उदाहरण में त्रुटि को ट्रिगर नहीं किया जा रहा है, लेकिन myPointer के मान का एक कॉउट करना अभी भी एक मेमोरी एड्रेस देता है?
  3. क्या # 3 वास्तव में काम करता है? मुझे काम करने लगता है, सूचक अब एक पते को संग्रहीत नहीं कर रहा है, क्या यह सूचक को हटाने का उचित तरीका है?

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


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

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

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

जवाबों:


168

1 & 2

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;

ऊपर वाले ने कुछ नहीं किया । जैसा कि सूचक ने NULL को बताया, आपने कुछ भी मुक्त नहीं किया।


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

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

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


सही तरीका:

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

बेहतर तरीका:

यदि आप C ++ का उपयोग कर रहे हैं, तो कच्चे पॉइंटर्स का उपयोग करें। इसके बजाय स्मार्ट पॉइंटर्स का उपयोग करें जो आपके लिए इन चीजों को थोड़ा ओवरहेड के साथ संभाल सकते हैं। C ++ 11 कई के साथ आता है ।


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

4
धन्यवाद, मैंने आपके उत्तर को a) के लिए चुना जो यह समझाता है कि क्या गलत था और b) एक सर्वोत्तम अभ्यास दे रहा है, बहुत बहुत धन्यवाद!
जियो

6
@ यह सही नहीं है। delete myPointerडील-डौल *myPointer। वह सही है। लेकिन myPointerएक स्मृति स्थान पर इंगित करना जारी है जिसे मुक्त कर दिया गया है और इसका उपयोग नहीं किया जाना चाहिए क्योंकि यह यूबी है। केवल स्कोप के अंत के बाद यह दुर्गम होगा यदि यह पहली बार में एक स्थानीय चर था।
अनिरुद्ध रामनाथन

2
@DarkCthulhu धन्यवाद! (मैं सचमुच) newहर दिन कुछ सीखता हूं । (मैं
खुश

1
@AmelSalibasic स्टैक पर चर के साथ जुड़ी मेमोरी को केवल एक बार मुक्त किया जाएगा जब यह दायरे से बाहर हो जाएगा। इसे निरुपित करना NULLहमें बाद में इसका दुरुपयोग करने से रोकता है।
अनिरुद्ध रामनाथन

23

मेरा मानना ​​है कि आप पूरी तरह से समझ नहीं पा रहे हैं कि पॉइंटर्स कैसे काम करते हैं।
जब आपके पास कुछ मेमोरी को इंगित करने वाला एक पॉइंटर होता है, तो तीन अलग-अलग चीजें होती हैं जिन्हें आपको समझना चाहिए:
- पॉइंटर (मेमोरी) द्वारा "जो बताया गया है"
- यह मेमोरी एड्रेस
- सभी पॉइंटर्स को अपनी मेमोरी डिलीट करने की आवश्यकता नहीं है: आप केवल स्मृति को हटाने की आवश्यकता थी जिसे गतिशील रूप से आवंटित किया गया था (प्रयुक्त 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.

C ++ आपको deleteएक पॉइंटर की कोशिश करता है जो इंगित nullकरता है लेकिन यह वास्तव में कुछ भी नहीं करता है, बस कोई त्रुटि नहीं देता है।


2
धन्यवाद, यह सुपर मददगार था, मैंने सोचा कि मैं सभी बिंदुओं को हटाने के लिए HAD था, यह नहीं जानता था कि केवल उन लोगों के लिए जो new'd थे, धन्यवाद।
तेंदुए

13

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

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

int *some_integers = new int[20000]

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

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

delete [] some_integers;

उम्मीद है की वो मदद करदे।


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

7

C ++ में एक नियम है, हर नए के लिए एक डिलीट है

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

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

myPointer = &myVar;

तुम कहो:

myPointer = myVar में डेटा कहाँ संग्रहीत है इसका पता

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

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

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

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

myPointer = NULL;

जो बराबर है:

myPointer = 0;

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

2
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
इसके अलावा, स्टैक फ्रेम youtube.com/watch?v=bjObm0hxIYY , और संकेत पर youtube.com/watch?v=Rxvv9krECNw पर इस व्याख्यान की जाँच करें ।
कैस्पर बेयर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.