दोनों के बीच एक महत्वपूर्ण अंतर है।
new
सी # में मूल्य प्रकारों के साथ बहुत अधिक व्यवहार नहीं किया गया है, और लोग अक्सर कहते हैं कि उन वस्तुओं को स्टैक पर आवंटित किया जाता है, जो शायद सबसे आम / स्पष्ट मामला है, लेकिन हमेशा सच नहीं है। अधिक सटीक रूप से, उपयोग किए बिना आवंटित वस्तुओं new
में स्वचालित भंडारण होता है। अवधि के
साथ आवंटित सब कुछ new
ढेर पर आवंटित किया गया है, और इसके लिए एक संकेतक लौटाया गया है, बिल्कुल सी # में संदर्भ प्रकारों की तरह।
स्टैक पर आबंटित किसी चीज का एक स्थिर आकार होता है, जिसे संकलन-समय पर निर्धारित किया जाता है (कंपाइलर को स्टैक पॉइंटर को सही ढंग से सेट करना होता है, या यदि ऑब्जेक्ट किसी अन्य वर्ग का सदस्य है, तो उसे उस अन्य वर्ग के आकार को समायोजित करना होगा) । इसीलिए C # में सरणियाँ संदर्भ प्रकार हैं। उन्हें होना चाहिए, क्योंकि संदर्भ प्रकारों के साथ, हम रनटाइम पर तय कर सकते हैं कि कितनी मेमोरी मांगनी है। और यहाँ भी वही लागू होता है। केवल स्थिर आकार (एक आकार जिसे संकलन-समय पर निर्धारित किया जा सकता है) के साथ स्वचालित भंडारण अवधि (स्टैक पर) के साथ आवंटित किया जा सकता है। डायनामिक रूप से आकार के सरणियों को कॉल करके, ढेर पर आवंटित किया जाना है new
।
(और यह वह जगह है जहाँ C # स्टॉप पर कोई समानता है)
अब, स्टैक पर आवंटित कुछ भी "स्वचालित" भंडारण अवधि है (आप वास्तव में एक चर के रूप में घोषित कर सकते हैं auto
, लेकिन यह डिफ़ॉल्ट है यदि कोई अन्य भंडारण प्रकार निर्दिष्ट नहीं किया गया है तो कीवर्ड वास्तव में अभ्यास में उपयोग नहीं किया जाता है, लेकिन यह वह जगह है जहां यह है से आता है)
स्वचालित भंडारण अवधि का अर्थ है कि यह कैसा लगता है, चर की अवधि स्वचालित रूप से नियंत्रित की जाती है। इसके विपरीत, ढेर पर आवंटित कुछ भी आपके द्वारा मैन्युअल रूप से हटा दिया जाना है। यहाँ एक उदाहरण है:
void foo() {
bar b;
bar* b2 = new bar();
}
यह फ़ंक्शन तीन मानों को ध्यान में रखते हुए बनाता है:
पंक्ति 1 पर, यह एक चर घोषित करता है b
bar
स्टैक (स्वचालित अवधि) पर प्रकार का ।
पंक्ति 2 पर, यह स्टैक (स्वचालित अवधि) पर एक bar
पॉइंटर घोषित करता है b2
, और नए को कॉल करता है, bar
जो ढेर पर एक ऑब्जेक्ट आवंटित करता है । (गतिशील अवधि)
जब फ़ंक्शन वापस आता है, तो निम्न होगा: सबसे पहले, b2
दायरे से बाहर चला जाता है (विनाश का क्रम हमेशा निर्माण के आदेश के विपरीत होता है)। लेकिन b2
सिर्फ एक सूचक है, इसलिए कुछ भी नहीं होता है, यह जो स्मृति रखता है वह बस मुक्त हो जाता है। और महत्वपूर्ण बात, यह जिस मेमोरी को इंगित करता है (a)bar
ढेर पर उदाहरण) को छुआ नहीं है। केवल पॉइंटर को मुक्त किया गया है, क्योंकि केवल पॉइंटर की स्वचालित अवधि थी। दूसरा, b
दायरे से बाहर हो जाता है, इसलिए चूंकि इसकी स्वचालित अवधि होती है, इसके विध्वंसक को कहा जाता है, और मेमोरी को मुक्त कर दिया जाता है।
और यह bar
ढेर पर उदाहरण? यह शायद अभी भी वहाँ है। किसी ने इसे हटाने की जहमत नहीं उठाई, इसलिए हमने मेमोरी लीक कर दी है।
इस उदाहरण से, हम देख सकते हैं कि स्वचालित अवधि के साथ कुछ भी गारंटी है को उसके विध्वंसक होने की दी जाती है जब वह दायरे से बाहर हो जाती है। यह उपयोगी है। लेकिन ढेर पर कुछ भी आवंटित किया जाता है जब तक हमें इसकी आवश्यकता होती है, और गतिशील रूप से आकार हो सकता है, जैसा कि सरणियों के मामले में होता है। वह भी उपयोगी है। हम अपनी मेमोरी आवंटन को प्रबंधित करने के लिए इसका उपयोग कर सकते हैं। क्या होगा अगर फू वर्ग ने अपने कंस्ट्रक्टर में ढेर पर कुछ मेमोरी आवंटित की, और उस मेमोरी को अपने विध्वंसक में हटा दिया। तब हम दोनों दुनिया के सबसे अच्छे, सुरक्षित मेमोरी आवंटन प्राप्त कर सकते थे, जिन्हें फिर से मुक्त करने की गारंटी दी जाती है, लेकिन हर चीज को स्टैक पर होने के लिए मजबूर करने की सीमाओं के बिना।
और यह बहुत अधिक सटीक है कि अधिकांश C ++ कोड कैसे काम करता है। मानक पुस्तकालय को देखेंstd::vector
उदाहरण लिए देखें। यह आमतौर पर स्टैक पर आवंटित किया जाता है, लेकिन गतिशील रूप से आकार और आकार बदल सकता है। और यह आवश्यक रूप से ढेर पर मेमोरी को आंतरिक रूप से आवंटित करके करता है। कक्षा का उपयोगकर्ता इसे कभी नहीं देखता है, इसलिए मेमोरी लीक करने का कोई मौका नहीं है, या जो आपने आवंटित किया है उसे साफ करना भूल गया है।
इस सिद्धांत को आरएआईआई कहा जाता है (संसाधन अधिग्रहण प्रारंभिक है), और इसे किसी भी संसाधन तक बढ़ाया जा सकता है जिसे अधिग्रहित और जारी किया जाना चाहिए। (नेटवर्क सॉकेट, फाइलें, डेटाबेस कनेक्शन, सिंक्रोनाइज़ेशन लॉक)। उन सभी को कंस्ट्रक्टर में अधिग्रहित किया जा सकता है, और विध्वंसक में जारी किया जा सकता है, इसलिए आपको गारंटी है कि आपके द्वारा प्राप्त सभी संसाधन फिर से मुक्त हो जाएंगे।
एक सामान्य नियम के रूप में, अपने उच्च स्तरीय कोड से सीधे नए / डिलीट का उपयोग कभी न करें। इसे हमेशा उस वर्ग में लपेटें जो आपके लिए मेमोरी का प्रबंधन कर सकता है, और जो यह सुनिश्चित करेगा कि यह फिर से मुक्त हो जाए। (हां, इस नियम के अपवाद हो सकते हैं। विशेष रूप से, स्मार्ट पॉइंटर्स के लिए आपको new
सीधे कॉल करने की आवश्यकता होती है , और पॉइंटर को इसके निर्माता को पास करना होता है, जो तब संभालता है और सुनिश्चित करता है delete
कि इसे सही ढंग से कहा जाता है। लेकिन यह अभी भी अंगूठे का एक बहुत ही महत्वपूर्ण नियम है। )