2008-09-19 18 views
52

सी ++ में, स्टैक का उपयोग करना सबसे अच्छा कब है? ढेर का उपयोग करना सबसे अच्छा कब है?ढेर के बजाय ढेर का उपयोग करना सबसे अच्छा है और इसके विपरीत?

+10

मुझे लगता है कि आप स्मृति संरचना आवंटित करने के लिए सिस्टम ढेर और सिस्टम ढेर का मतलब है, डेटा संरचना ढेर और ढेर नहीं, सही? –

उत्तर

53

स्टैक का उपयोग करें जब वर्तमान चर रिटर्न के बाद आपके चर का उपयोग नहीं किया जाएगा। वर्तमान कार्य के जीवनकाल से परे चर में डेटा की आवश्यकता होने पर ढेर का उपयोग करें।

+3

हालांकि इसके आसपास जाने के तरीके हैं। एक फ़ंक्शन को एक बफर पास करना जो उसके बाद डेटा लिखता है, एक फंक्शन "रिटर्न" गतिशील डेटा रखने का एक अच्छा तरीका है जो कम स्टैक फ्रेम में रहता है। यह ओओ की तरह कम है, लेकिन यह अधिक कुशल है। –

+6

आकार भी एक विचार है: ढेर पर 1K से अधिक कुछ सावधानी से विचार किया जाना चाहिए। कभी-कभी स्मृति को ढेर करने के लिए एक स्टैक पॉइंटर होना बेहतर होता है (साथ ही 'रिसोर्स अधिग्रहण प्रारंभिक' idiom के साथ) – Arkadiy

+1

लेकिन जब स्मृति कक्षा की संपत्ति होती है, तो आप कैसे निर्णय लेते हैं कि क्लास प्रॉपर्टी पॉइंटर या अन्यथा कब होनी चाहिए? इसके अलावा आप एक स्मार्ट सूचक का उपयोग कब कर सकते हैं? – JagWire

3

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

आपके पास कम मॉलोक() कथन है, मेमोरी लीक के लिए कम संभावनाएं हैं।

4

यह प्रश्न संबंधित है (हालांकि वास्तव में एक डुप्ली नहीं) What and where are the stack and heap पर, जिसे कुछ दिन पहले पूछा गया था।

0

प्रश्न बीमार गठित है।

ऐसी स्थितियां हैं जहां आपको ढेर की आवश्यकता होती है, अन्य जहां आपको ढेर की आवश्यकता होती है, अन्य जहां आपको स्थिर भंडारण की आवश्यकता होती है, अन्य जहां आपको कॉन्स मेमोरी डेटा की आवश्यकता होती है, अन्य जहां आपको मुफ्त स्टोर की आवश्यकता होती है।

ढेर तेजी से है, क्योंकि आवंटन एसपी पर सिर्फ "वृद्धि" है, और सभी "आवंटन" आपके द्वारा किए गए फ़ंक्शन के आमंत्रण समय पर किया जाता है। हीप (या फ्री स्टोर) आवंटन/डेलोकेशन अधिक समय होता है महंगा और त्रुटि प्रवण।

28

अंगूठे के नियम के रूप में, ढेर पर विशाल वस्तुओं को बनाने से बचें।

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

स्टैक का उपयोग करें जब स्मृति का उपयोग किया जा रहा है, उस क्षेत्र तक सख्ती से सीमित है जिसमें आप इसे बना रहे हैं। यह स्मृति रिसाव से बचने के लिए उपयोगी है क्योंकि आप जानते हैं कि आप स्मृति का उपयोग कहां करना चाहते हैं, और आपको पता है कि आपको इसकी आवश्यकता नहीं है, इसलिए स्मृति आपके लिए साफ हो जाएगी।

int main() 
{ 
    if (...) 
    { 
     int i = 0; 
    } 
    // I know that i is no longer needed here, so declaring i in the above block 
    // limits the scope appropriately 
} 

ढेर, तथापि, जब अपनी स्मृति इसके निर्माण के दायरे से बाहर पहुँचा जा सकता है और आप एक ढेर चर नकल करने की इच्छा नहीं उपयोगी है। यह आपको स्पष्ट नियंत्रण दे सकता है कि स्मृति आवंटित और अस्वीकृत कैसे किया जाता है।

Object* CreateObject(); 

int main() 
{ 
    Object* obj = CreateObject(); 
    // I can continue to manipulate object and I decide when I'm done with it 

    // .. 
    // I'm done 
    delete obj; 
    // .. keep going if you wish 
    return 0; 
} 

Object* CreateObject() 
{ 
    Object* returnValue = new Object(); 
    // ... do a bunch of stuff to returnValue 
    return returnValue; 
    // Note the object created via new here doesn't go away, its passed back using 
    // a pointer 
} 

स्पष्ट रूप से यहां एक आम समस्या यह है कि आप अपनी वस्तु को हटाना भूल सकते हैं। इसे मेमोरी रिसाव कहा जाता है। ये समस्याएं अधिक प्रचलित हैं क्योंकि आपका प्रोग्राम कम और कम छोटा हो जाता है जहां "स्वामित्व" (या चीजों को हटाने के लिए वास्तव में कौन जिम्मेदार है) परिभाषित करना अधिक कठिन हो जाता है।

अधिक प्रबंधित भाषाओं (सी #, जावा) में सामान्य समाधान कचरा संग्रहण लागू करना है ताकि आपको चीजों को हटाने के बारे में सोचना न पड़े।हालांकि, इसका मतलब है पृष्ठभूमि में कुछ ऐसा है जो आपके ढेर डेटा को जांचने के लिए aperiodically चलाता है। एक गैर-तुच्छ कार्यक्रम में, यह "कचरा संग्रह" धागा पॉप अप हो जाता है और चग्स के रूप में बल्कि अक्षम हो सकता है, हटाए जाने वाले डेटा की तलाश में, जबकि आपका शेष प्रोग्राम निष्पादित करने से अवरुद्ध हो जाता है।

सी ++ में, स्मृति लीक से निपटने के लिए सबसे आम, और सर्वोत्तम (मेरी राय में) समाधान एक स्मार्ट सूचक का उपयोग करना है। इनमें से सबसे आम boost::shared_ptr जो है (reference counted)

तो ऊपर बढ़ावा :: shared_ptr CreateObject उदाहरण बनाना() है;

int main() 
{ 
    boost::shared_ptr<Object> obj = CreateObject(); 
    // I can continue to manipulate object and I decide when I'm done with it 

    // .. 
    // I'm done, manually delete 
    obj.reset(NULL); 
    // .. keep going if you wish 
    // here, if you forget to delete obj, the shared_ptr's destructor will note 
    // that if no other shared_ptr's point to this memory 
    // it will automatically get deleted. 
    return 0; 
} 

boost::shared_ptr<Object> CreateObject() 
{ 
    boost::shared_ptr<Object> returnValue(new Object()); 
    // ... do a bunch of stuff to returnValue 
    return returnValue; 
    // Note the object created via new here doesn't go away, its passed back to 
    // the receiving shared_ptr, shared_ptr knows that another reference exists 
    // to this memory, so it shouldn't delete the memory 
} 
+0

और फिर वहां चलने वाले अर्थ थे –

4

अंगूठे के नियम के रूप में जब भी आप कर सकते हैं स्टैक का उपयोग करें। यानी जब उस दायरे के बाहर परिवर्तनीय की आवश्यकता नहीं होती है।

इसकी तेज़ी से, कम विखंडन का कारण बनता है और कॉलिंग मॉलोक या नए से जुड़े अन्य ओवरहेड से बचने जा रहा है। ढेर से आवंटित करना एक असेंबलर ऑपरेशंस का एक जोड़ा है, मॉलोक या नया एक कुशल कार्यान्वयन में कोड की कई सौ रेखाएं हैं।

यह ढेर का उपयोग करने के लिए कभी भी सबसे अच्छा नहीं है ... बस अपरिहार्य है। :)

+0

यह कुछ असेंबलर ऑपरेशंस से बेहतर है - यह केवल एक जोड़ या घटाना है (इस आधार पर कि आपका स्टैक किस दिशा में बढ़ता है)। – Eclipse

+0

जोड़ता है और घटाव हमेशा एकल ओप नहीं होते हैं ... लेकिन दूसरे छोर पर साफ-सफाई पर भी विचार करते हैं। कॉल कन्वेंशन के आधार पर ऐड/सब से मेल खाने के लिए एक उप/ऐड होने जा रहा है, हालांकि इन सभी को समेकित किया जा सकता है कि आप कैसे स्टैक का उपयोग करते हैं और संकलक क्या अनुकूलन करता है (यह वास्तव में शून्य निर्देशों तक उबाल सकता है। .. या बहुत विशेष मामलों में, ऋण निर्देश) – jheriko

8

नियम यह है कि ऊपर उल्लेख किया है आप स्थानीय चर कि समारोह के दायरे से बाहर की जरूरत नहीं कर रहे हैं के लिए ढेर का उपयोग आम तौर पर करना चाहिए के लिए एक अपवाद:

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

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