पहले, याद रखें C++ वस्तुओं हो सकता है कि ढेर पर या तो ढेर पर या पर बनाया गया।
एक स्टैक फ्रेम (या स्कोप) एक बयान द्वारा परिभाषित किया गया है। यह एक फ़ंक्शन या फ्लो कंट्रोल ब्लॉक (while
/if
/for
इत्यादि के रूप में छोटा हो सकता है) के रूप में बड़ा हो सकता है। एक मनमाने ढंग से {}
कोड के मनमानी ब्लॉक को संलग्न करने वाली जोड़ी भी एक ढेर फ्रेम का गठन करती है। एक फ्रेम के भीतर परिभाषित कोई स्थानीय वैरिएबल उस फ्रेम से बाहर निकलने के बाद गुंजाइश से बाहर हो जाएगा। जब एक स्टैक वैरिएबल गुंजाइश से बाहर हो जाता है, तो इसके विनाशक को बुलाया जाता है।
तो यहाँ
ढेर फ्रेम (एक समारोह के निष्पादन) और एक स्थानीय चर के भीतर घोषित, जो एक बार स्टैक फ्रेम बाहर निकलता क्षेत्र से बाहर जाना होगा का एक उत्कृष्ट उदाहरण है - एक बार समारोह खत्म:
void bigSideEffectGuy() {
BigHeavyObject b (200);
b.doSomeBigHeavyStuff();
}
bigSideEffectGuy();
// a BigHeavyObject called b was created during the call,
// and it went out of scope after the call finished.
// The destructor ~BigHeavyObject() was called when that happened.
if (myCondition) {
Circle c (20);
c.draw();
}
// c is now out of scope
// The destructor ~Circle() has been called
के एक ढेर-निर्मित वस्तु के लिए एक ही रास्ता "दायरे में रहने" के बाद फ्रेम से बाहर निकल गया है:
एक उदाहरण है जहाँ हम देखते हैं एक ढेर फ्रेम सिर्फ एक if
बयान के शरीर किया जा रहा है अगर यह एक समारोह का वापसी मूल्य है। लेकिन यह वास्तव में "गुंजाइश में शेष नहीं है" क्योंकि वस्तु की प्रतिलिपि बनाई जा रही है। तो मूल दायरे से बाहर चला जाता है, लेकिन एक प्रति बना दिया जाता है। उदाहरण:
Circle myFunc() {
Circle c (20);
return c;
}
// The original c went out of scope.
// But, the object was copied back to another
// scope (the previous stack frame) as a return value.
// No destructor was called.
अब, एक वस्तु को ढेर पर भी घोषित किया जा सकता है। इस चर्चा के लिए, ढेर के बारे में सोचें स्मृति की एक असभ्य ब्लॉब के रूप में। स्टैक के विपरीत, जो आपके द्वारा दर्ज की जाने वाली आवश्यक स्मृति को स्वचालित रूप से आवंटित और डी-आवंटित करता है, आपको मैन्युअल रूप से आरक्षित और मुक्त ढेर मेमोरी चाहिए।
ढेर पर घोषित एक वस्तु, फैशन के बाद, स्टैक फ्रेम के बीच "जीवित" होती है। कोई कह सकता है कि ढेर पर घोषित एक वस्तु कभी भी गुंजाइश से बाहर नहीं जाती है, लेकिन यह वास्तव में है क्योंकि वस्तु वास्तव में किसी भी दायरे से जुड़ी नहीं है। ऐसी वस्तु new
कीवर्ड के माध्यम से बनाई जानी चाहिए, और इसे एक सूचक द्वारा संदर्भित किया जाना चाहिए।
एक बार जब आप इसके साथ काम कर लें तो हेप ऑब्जेक्ट को मुक्त करना आपकी ज़िम्मेदारी है। delete
कीवर्ड के साथ आप मुफ्त ढेर ऑब्जेक्ट्स। एक ढेर ऑब्जेक्ट पर विनाशक तब तक नहीं बुलाया जाता जब तक आप ऑब्जेक्ट को मुक्त नहीं करते।
पॉइंटर्स जो ढेर ऑब्जेक्ट्स को संदर्भित करते हैं वे आमतौर पर स्कॉप्स से जुड़े स्थानीय चर होते हैं। एक बार जब आप ढेर ऑब्जेक्ट का उपयोग कर लेंगे, तो आप पॉइंटर (ओं) को दायरे से बाहर जाने के लिए संदर्भित करने की अनुमति देते हैं। यदि आपने ऑब्जेक्ट को स्पष्ट रूप से मुक्त नहीं किया है, तो पॉइंटर इंगित कर रहा है, तो प्रक्रिया से बाहर निकलने तक हीप मेमोरी का ब्लॉक कभी भी मुक्त नहीं होगा (इसे मेमोरी रिसाव कहा जाता है)।
इस बारे में सोचें: स्टैक पर बनाई गई वस्तु एक कमरे में कुर्सी पर टैप किए गए गुब्बारे की तरह है। जब आप कमरे से बाहर निकलते हैं, तो गुब्बारा स्वचालित रूप से पॉप हो जाता है। ढेर पर बनाई गई वस्तु एक रिबन पर एक गुब्बारे की तरह है, जो एक कमरे में कुर्सी से बंधी हुई है। रिबन सूचक है। जब आप कमरे से बाहर निकलते हैं, तो रिबन स्वचालित रूप से गायब हो जाता है, लेकिन गुब्बारा सिर्फ छत पर तैरता है और अंतरिक्ष लेता है। उचित प्रक्रिया एक पिन के साथ गुब्बारे को पॉप करना है, और फिर कमरे से बाहर निकलना है, जहां रिबन गायब हो जाएगा।लेकिन, स्ट्रिंग पर गुब्बारे के बारे में अच्छी बात यह है कि आप रिबन को भी खोल सकते हैं, इसे अपने हाथ में रख सकते हैं, और कमरे से बाहर निकल सकते हैं और गुब्बारा अपने साथ ले सकते हैं।
तो अपनी लिंक्ड सूची उदाहरण पर जाने के लिए: आम तौर पर, ऐसी सूची के नोड्स को ढेर पर घोषित किया जाता है, जिसमें प्रत्येक नोड अगले नोड पर पॉइंटर धारण करता है। यह सब ढेर पर बैठा है और कभी भी गुंजाइश से बाहर नहीं जाता है। गुंजाइश से बाहर निकलने वाली एकमात्र चीज वह सूचक है जो सूची की जड़ को इंगित करती है - जो सूचक आप पहली जगह सूची में संदर्भित करने के लिए उपयोग करते हैं। वह गुंजाइश से बाहर जा सकता है।
यहाँ ढेर पर सामान बनाने का एक उदाहरण है, और जड़ सूचक दायरे से बाहर जा रहा है:
if (myCondition) {
Node* list_1 = new Node (3);
Node* list_2 = new Node (4);
Node* list_3 = new Node (5);
list_1->next = list_2;
list_2->next = list_3;
list_3->next = null;
}
// The list still exists
// However list_1 just went out of scope
// So the list is "marooned" as a memory leak
आपका अद्यतन सवाल एक बहुत अच्छा एक है, और जवाब है नहीं। जब कोई सूचक स्कोप से बाहर हो जाता है, तो ऑब्जेक्ट का विनाशक जिस पर यह इंगित कर रहा है ** ** ** स्वचालित रूप से नहीं बुलाया जाता है। आपको इसे स्वयं कॉल करना होगा, और ऐसा तब होता है जब आप स्मृति को मुक्त करने के लिए नोड पर 'हटाएं' कहते हैं। जब आप सार्थक विनाशक कार्यान्वयन के साथ ऑब्जेक्ट्स में पॉइंटर्स की सरणी या सूची रखते हैं, तो यह ध्यान में रखना एक अच्छी बात है। सौभाग्य से, चूंकि आपको इन्हें स्वयं भी 'मुक्त' करना है, इसलिए आप विनाशकों को ट्रिगर करेंगे। –
वैसे, अगर आपको वास्तव में किसी चीज़ के लिए एक लिंक्ड सूची की आवश्यकता है, तो आप अपनी खुद की कस्टम लिंक्ड सूची की तुलना में std :: सूची का उपयोग करके बहुत बेहतर हैं। – DSimon
मुझे 'मुक्त' के बजाय 'हटाएं' कहा जाना चाहिए था। 'मुक्त' को अनदेखा करें, यह सी विरासत है। ढेर आवंटन/हटाने के लिए केवल 'नया' और 'हटाएं' का प्रयोग करें। –