2009-12-10 10 views
5

मैं थोड़ी देर के लिए सी ++ का उपयोग कर रहा हूं। मैं सिर्फ यकीन है कि कैसे स्मृति प्रबंधन काम करता है कभी नहीं कर रहा हूँ इसलिए यहाँ यह जाता है:सी ++ में मेमोरी से चर हटा दिए जाने पर?

int addTwo(int num) 
{ 
    int temp = 2; 
    num += temp; 
    return num; 
} 
तो इस उदाहरण में

:

मैं सभी अनिश्चित के पहले कैसे स्मृति एक समारोह, पूर्व में आवंटित नहीं की गई है कर रहा हूँ फ़ंक्शन समाप्त होने के बाद मेमोरी से अस्थायी हटा दिया जाएगा? यदि नहीं, यह कैसे किया जाता है। सी # में एक चर का उपयोग होने के बाद एक चर हटा दिया जाता है। क्या मुझे कोई अन्य मामले भी पता होना चाहिए?

धन्यवाद

+0

'सी' के रूप में पुनः प्राप्त किया गया क्योंकि यहां कोई और C++ नहीं है, जैसा कि नीचे किसी और द्वारा इंगित किया गया है। – ChrisInEdmonton

+5

सी ++ के रूप में टेटाग किया गया, क्योंकि यह निश्चित रूप से एक सी ++ प्रश्न है, और प्रश्नकर्ता स्पष्ट रूप से सी ++ के बारे में पूछता है। –

+8

ओपी, कोई आवश्यकता नहीं है कि आप किसी भी उत्तर को स्वीकार करें। –

उत्तर

7

स्थानीय चर temp समारोह की शुरुआत में एक ढेर पर "धक्का दे दिया" जाता है और ढेर जब समारोह बाहर जाने का "पॉप"।

यहाँ एक गैर अनुकूलित संस्करण से एक disassembly है:

int addTwo(int num) 
{ 
00411380 push  ebp 
00411381 mov   ebp,esp    //Store current stack pointer 
00411383 sub   esp,0CCh   //Reserve space on stack for locals etc 
00411389 push  ebx 
0041138A push  esi 
0041138B push  edi 
0041138C lea   edi,[ebp-0CCh] 
00411392 mov   ecx,33h 
00411397 mov   eax,0CCCCCCCCh 
0041139C rep stos dword ptr es:[edi] 
    int temp = 2; 
0041139E mov   dword ptr [temp],2 
    num += temp; 
004113A5 mov   eax,dword ptr [num] 
004113A8 add   eax,dword ptr [temp] 
004113AB mov   dword ptr [num],eax 
    return num; 
004113AE mov   eax,dword ptr [num] 
} 
004113B1 pop   edi 
004113B2 pop   esi 
004113B3 pop   ebx 
004113B4 mov   esp,ebp     //Restore stack pointer 
004113B6 pop   ebp 
004113B7 ret   

शब्द "धक्का दे दिया" और "पॉप" केवल एक सादृश्य के रूप में होती हैं। जैसा कि आप असेंबली आउटपुट से देख सकते हैं, कंपाइलर स्थानीय वैरिएबल इत्यादि के लिए सभी मेमोरी को स्टैक पॉइंटर से उपयुक्त मान घटाकर एक बार में सुरक्षित रखता है।

+3

सटीक रूप से ढेर का उपयोग कैसे किया जाता है। फंक्शन कॉल स्टैक पर एक फ्रेम आवंटित करेगा, लेकिन कोई धक्का और पॉप नहीं होगा। –

+1

@Neil मुझे पता है, यह एक समानता के रूप में था जो समझना आसान होगा। जोड़ा गया उद्धरण और कुछ असेंबली आउटपुट –

+2

पुश + पॉप केवल अवधारणाएं हैं - निश्चित अस्थायी स्टैक को धक्का दिया जाता है/पॉप किया जाता है। कार्यान्वयन कंपाइलर + आर्किटेक्चर निर्भर होता है, और आम तौर पर आप उम्मीद कर सकते हैं कि पूरा फ्रेम "धक्का" और "पॉप" किया जाएगा। ऐतिहासिक कारणों से स्टैक कार्यान्वयन का ध्यान ऐसा होता है कि शब्दावली का प्रयोग अलग-अलग होता है, लेकिन हम अभी भी अंतिम-प्रथम-प्रथम डेटा संरचना से डेटा रखने और हटाने के बारे में बात कर रहे हैं: पुश और पॉप निश्चित रूप से * गलत * शब्द नहीं हैं उसके लिए। –

0

परिवर्तनीय अस्थायी आवंटित स्टैक है। इसका मतलब है कि फ़ंक्शन लौटने पर इसे हटा दिया जाता है। उदाहरण के लिए:

देखें .:

+0

पुन: सी # जो सभी वस्तुओं के बारे में सच नहीं है, कुछ संदर्भ प्रकार (कक्षाएं) हैं और कुछ मूल्य प्रकार (structs, primatives, enums) हैं। टिप्पणी के लिए –

+0

धन्यवाद। तदनुसार मेरी प्रतिक्रिया संपादित की। – Sebastian

+0

डाउनवॉट्स क्यों? इस जवाब में क्या गलत है? –

11

यहाँ, temp ढेर पर आवंटित किया जाता है, और याद है कि इसे इस्तेमाल करता है स्वचालित रूप से मुक्त हो जाता है जब समारोह बाहर निकलता है। हालांकि, अगर आप इसे इस तरह ढेर पर आवंटित कर सकते हैं:

int *temp = new int(2); 

यह मुक्त करने के लिए आपको

delete temp; 

करने के लिए आप ढेर पर अपने चर आवंटित तो है, यह क्या आम तौर पर होता है:

जब आप अपना फ़ंक्शन कॉल करते हैं, तो यह 'स्टैक पॉइंटर' नामक इस चीज़ को बढ़ाएगा - एक संख्या कह रही है जो स्मृति में पते को स्थानीय चर द्वारा उपयोग के लिए 'संरक्षित' होना है। जब फ़ंक्शन वापस आता है, तो यह स्टैक पॉइंटर को इसके मूल मान में घटा देगा। वास्तव में उस फ़ंक्शन में आवंटित चर के लिए कुछ भी नहीं किया जाता है, सिवाय इसके कि वे जो स्मृति में रहते हैं वह अब 'संरक्षित' नहीं है - और कुछ भी (और अंत में) उन्हें ओवरराइट कर सकता है। तो अब आप उन्हें अब तक नहीं पहुंच पाएंगे।

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

+2

उस उदाहरण में, अस्थायी को एक सूचक होने की आवश्यकता होगी। –

+5

int temp = new int (2); सी ++ –

+0

में गलत वाक्यविन्यास है, जो निश्चित, 15char) – int3

4

temp स्टैक पर आवंटित किया गया है। तो जब समारोह वापस आता है, यह चला गया है।

सी ++ स्कोप नियम सी # के समान हैं।

+1

नाइटपिक करने के लिए, मैं कहूंगा कि सी # स्कोप नियम सी ++ के समान हैं क्योंकि सी ++ सी # से पहले आया था। –

+0

जैसा कि मुझे पता है, उतना ही कम्यूटिव है। –

6

फ़ंक्शन से बाहर निकलने के बाद इसे स्मृति से हटाया नहीं गया है।

यह स्मृति में रहता है, addTwo के ढेर फ्रेम में जब तक किसी अन्य प्रक्रिया (या समान) फिर से स्मृति के उस भाग का उपयोग करता है।

उस समय तक, अस्थायी तक पहुँचने अपरिभाषित व्यवहार है।

+4

सच है, और यह कुछ काम के लिए महत्वपूर्ण हो सकता है। हालांकि, हम में से अधिकांश के लिए, अवधारणात्मक रूप से कार्य द्वारा पूरा होने के बाद अस्थायी रूप से उपयोग की जाने वाली स्मृति उपलब्ध नहीं होती है। – tloach

+1

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

+0

@ एमन: मेरा मतलब था कि कुछ काम के लिए यह जानना महत्वपूर्ण है कि आपका स्टैक आकार केवल इसलिए नहीं हट जाएगा क्योंकि स्थानीय चर का एक गुच्छा गुंजाइश से बाहर हो जाता है। हार्डवेयर पर काम करने वाले लोगों के लिए जहां हर बाइट मामले इस व्यवहार से अवगत हैं, वे ढेर या ढेर पर स्थान आवंटित करने के फैसले को सूचित कर सकते हैं। – tloach

0

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

+0

+1 यह इंगित करने के लिए कि संख्या भी स्थानीय है। – ChrisInEdmonton

0

सी में, सी ++ स्थानीय चरस्वत: भंडारण वर्ग है और ढेर में संग्रहीत हैं।

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

यह सिर्फ ढेर में और स्मृति पर के लिए स्थानीय वास्तव में निकाल दिया जाता है सूचक हेरफेर ढेर है।

+0

असल में, सी ++ विनिर्देश में स्टैक स्टोरेज का कोई उल्लेख नहीं है। एकमात्र उल्लेख वैरिएबल की अवधि है। –

15

C++ में वहाँ अंगूठे का एक बहुत ही सरल नियम है:

सभी स्मृति स्वचालित रूप से मुक्त हो जाता है जब यह क्षेत्र से बाहर चलाता है, जब तक यह मैन्युअल रूप से आवंटित किया गया है।

मैनुअल आवंटन:

  • नई द्वारा आवंटित किसी भी वस्तु() चाहिए एक मिलान द्वारा डी-आवंटित किया हटाना()।
  • malloc() द्वारा आवंटित कोई भी स्मृति एक मिलान मुक्त() द्वारा आवंटित की जानी चाहिए।

सी ++ में एक बहुत ही उपयोगी डिजाइन पैटर्न आरए II (Resource Acquisition Is Initialization) जो एक scoped उद्देश्य यह है कि इसके नाशक में आवंटन को मुक्त कर देते करने के लिए गतिशील आवंटन बांधता है कहा जाता है।

आरए II कोड में आप हटाना बुला() या मुक्त(), क्योंकि वे स्वचालित रूप से कहा जाता है कि जब भी "लंगर वस्तु" क्षेत्र से बाहर चलाता है के बारे में चिंता की जरूरत नहीं है।

1

कृपया इस प्रश्न का मेरा जवाब देखें। यह ओयू के लिए बहुत सी चीजों को साफ़ कर सकता है।

How does automatic memory allocation actually work in C++?

मैं बस गिगल्स के लिए लिंक नहीं पोस्ट कर रहा हूँ। मेरा जवाब एक गहन रूप से दिखता है (एक बहुत ही प्रारंभिक स्तर पर) स्मृति प्रबंधन कैसे काम करता है।

0

सी ++, किसी भी वस्तु है कि आप किसी भी दायरे में घोषित में हटाया नहीं जाएगा जब दायरे वाले रास्ते। नीचे दिए गए उदाहरण में, जब आप ऑब्जेक्ट घोषित करते हैं तो डिफॉल्ट कन्स्ट्रक्टर को कॉल किया जाता है और विनाशक को बाहर निकलने पर कहा जाता है, यानी ~ MyClass।

void foo() { 
    MyClass object; 
    object.makeWonders(); 
} 

आप एक समारोह में एक सूचक की घोषणा करते हैं, तो सूचक ही (32 बिट सिस्टम के लिए 4 बाइट्स) पुन: दावा हो जाता है जब दायरे वाले रास्ते, लेकिन स्मृति आप ऑपरेटर नए या malloc का उपयोग आवंटित हो सकता रहना होगा - इसे अक्सर स्मृति रिसाव के रूप में जाना जाता है।

void foo() { 
    MyClass* object = new MyClass; 
    object->makeWonders(); 
    // leaking sizeof(MyClass) bytes. 
} 

तुम सच में नए के माध्यम से एक वस्तु जब यह बाहर निकालता गुंजाइश तो तुम इतनी तरह बढ़ावा :: scoped_ptr का उपयोग करना चाहिए हटाना आवश्यक है कि आवंटित करना आवश्यक है:

void foo() { 
    boost::scoped_ptr<MyClass> object(new MyClass); 
    object->makeWonders(); 
    // memory allocated by new gets automatically deleted here. 
} 
1

आम तौर पर स्मृति प्रबंधन में प्रयोग किया जाता है कि सामान्य कोड सी ++ में से

new 
malloc 

बनाई गई है गतिशील स्मृति के संदर्भ हर दूसरे भाषा की तरह व्यवहार करता है। यदि आप एक चर बनाते हैं या इसे वापस करते हैं, तो यह लक्ष्य पक्ष पर कॉपी और सुलभ है।

int a = addTwo(3); 

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

एक अतिरिक्त टिप्पणी जो महत्वपूर्ण

void func(std::string abc) 
{ 
    // method gets a copy of abc 
} 

void func(std::string& abc) 
{ 
    // method gets the original string object which can be modified without having to return it 
} 

void func(const std::string& abc) 
{ 
    // method gets the original string object abc but is not able to modify it  
} 

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

उदा।

bool CmpString(std::string a, std::string b) 
{ 
    return a.compare(b); 
} 

वास्तव में महंगा है क्योंकि स्ट्रिंग्स ए और बी हमेशा कॉपी की जाती हैं।

bool CmpString(const std::string& a, const std::string& b) 

का उपयोग करें।

यह महत्वपूर्ण है क्योंकि डिफ़ॉल्ट रूप से कोई भी प्रतिबिंबित वस्तुओं का उपयोग नहीं किया जाता है।

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

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