2009-06-08 13 views
5

मैं वैक्टरों के संबंध में स्मृति प्रबंधन के साथ बहुत उलझन में हूं और कुछ बुनियादी अवधारणाओं को समझा सकता हूं।सी ++ मेमोरी प्रबंधन और वैक्टर

मेरे पास एक ऐसा प्रोग्राम है जो बड़े वैक्टर का उपयोग करता है। मैं नई ऑपरेटर के साथ वैक्टर बनाया है और उन्हें के साथ कार्यक्रम के अंत में जारी हटाना स्मृति वापस पाने के लिए।

मेरा प्रश्न है, अगर कार्यक्रम दुर्घटनाओं या जो भी कारण के लिए निरस्त किया जाता है, हटाना लाइनों याद किया जाएगा, वहाँ भी इस परिदृश्य में स्मृति ठीक करने के लिए एक तरीका है।

मैं भी कुछ अन्य बड़े वैक्टर कि मैं नई कीवर्ड के बिना आवंटित की है। मैंने पढ़ा है कि ये ढेर पर बनाए जाएंगे, लेकिन वैसे भी स्मृति प्रबंधन को 'हुड के नीचे' के साथ निपटाया जाना चाहिए। हालांकि मुझे यकीन नहीं है कि यह हर बार जब मैं अपना प्रोग्राम चलाता हूं तो मैं राम खो देता हूं।

तो मेरी दूसरा सवाल नई कीवर्ड के बिना बनाया वैक्टर वास्तव में अपने स्वयं के उपकरणों के लिए छोड़ा जा सकता है और यहां तक ​​कि अगर कोड मध्य प्रवाह निरस्त किया गया है खुद को बाद स्पष्ट करने के लिए पर भरोसा किया, है।

और मैं एक तिहाई सवाल है कि बस मन में उभर गया है, अगर वाहक स्वचालित रूप से ढेर पर बनाई गई हैं क्यों तुम कभी नई उन लोगों के साथ कीवर्ड का प्रयोग करेंगे है लगता है? पढ़ने के लिए धन्यवाद, बेन

+2

"हर बार जब मैं अपना प्रोग्राम चलाता हूं तो मैं राम खो देता हूं" क्या आपका मतलब है "जब तक मैं प्रोग्राम से बाहर नहीं निकलता तब तक मेरी उपलब्ध रैम छोटी हो जाती है" या "प्रोग्राम से बाहर निकलने के बाद भी मेरी उपलब्ध रैम छोटी हो जाती है, और यह भी छोटा हो जाता है अगली बार जब मैं दौड़ता हूं, एक दिन तक मुझे बिल्कुल कोई रैम नहीं छोड़ा जाएगा "? –

+0

मै मैक्स का सवाल दूसरा कर रहा हूं। विंडोज़ मेरा मानना ​​है कि वास्तव में समाप्त होने वाले कार्यक्रमों को अनलोड नहीं किया जाता है जब तक कि इसे आवश्यकता न हो। इस तरह वे पहली बार जल्दी शुरू हो जाते हैं। –

+0

"और मुझे लगता है कि एक तीसरा सवाल जो सिर्फ दिमाग में उग आया है, अगर वेक्टर स्वचालित रूप से ढेर पर बनाए जाते हैं तो आप कभी भी उनके साथ नए कीवर्ड का उपयोग क्यों करेंगे?" आपको केवल ऐसा करने की आवश्यकता होगी यदि आपको मौजूदा क्षेत्र के बाहर वेक्टर को पास करने की आवश्यकता है। यह अभ्यास में अपेक्षाकृत दुर्लभ है। – rlbond

उत्तर

13

मुझे संदेह है कि आपके प्रश्न std :: vector < टी> (एक सरणी टी [] के विपरीत) के बारे में हैं।

  1. जब आपका एप्लिकेशन किसी भी कारण से क्रैश हो जाता है या निरस्त हो जाता है, तो ओएस स्मृति को पुनः प्राप्त करता है। यदि नहीं, तो आप वास्तव में दुर्लभ ओएस का उपयोग कर रहे हैं और एक बग की खोज की है।
  2. आपको वेक्टर द्वारा उपयोग की गई स्मृति और इसकी निहित वस्तुओं की स्मृति के बीच अंतर करने की आवश्यकता है। जैसा कि आपने नोट किया है, वेक्टर को ढेर या ढेर पर बनाया जा सकता है, जो इसके निहित तत्वों के लिए आवंटित स्मृति हमेशा ढेर पर होती है (जब तक कि आप अपना स्वयं का आवंटक प्रदान न करें जो कुछ और करता है)। वेक्टर द्वारा आवंटित स्मृति को वेक्टर के कार्यान्वयन द्वारा प्रबंधित किया जाता है, और यदि वेक्टर को नष्ट कर दिया जाता है (या तो क्योंकि यह ढेर पर वेक्टर के दायरे से बाहर हो जाता है या क्योंकि आप ढेर पर वेक्टर हटाते हैं) इसके विनाशक यह सुनिश्चित करते हैं कि सभी स्मृति मुक्त है।
+1

अधिकांश एम्बेडेड ओएस और कई आरटीओएस प्रक्रिया को क्रैश होने पर संसाधनों को साफ़ नहीं करते हैं। –

3

आपके प्रोग्राम द्वारा बनाई गई कोई भी स्मृति रिलीज होने पर रिलीज़ हो जाएगी। यह ऑपरेटिंग सिस्टम की एक विशेषता है, जो आप प्रोग्रामिंग भाषा के साथ कुछ भी नहीं कर रहे हैं।

"हर बार जब मैं अपना प्रोग्राम चलाता हूं तो मैं राम को ढीला करता हूं" किसी अन्य प्रभाव के कारण होना चाहिए - आप इसे कैसे माप रहे हैं?

तुम क्यों प्रयोग करेंगे 'नई' के रूप में - दो कारणों से:

  • आप जब वे
  • आप उन्हें वर्तमान समारोह बाहर निकलता है के बाद बनाए रखना चाहते मुक्त कर दिया जाता है पर नियंत्रण करना चाहते हैं।
+1

टोबीस को दिए गए समान टिप्पणी।एक प्रक्रिया दुर्घटनाग्रस्त होने पर अधिकतर एम्बेडेड ओएस और कई आरटीओएस संसाधनों को साफ नहीं करते हैं। –

+0

+1 यह इंगित करने के लिए कि कितने लोगों को एहसास नहीं है। वर्चुअल मेमोरी मैनेजर अक्सर एक लक्जरी है जिसे अक्सर मंजूरी दी जाती है। – Void

3

मुझे लगता है कि आप std :: वेक्टर के बारे में बात करते हैं और भाषा सरणी के बारे में नहीं।

  1. एक कार्यक्रम दुर्घटनाओं, ओएस अपनी स्मृति
  2. std :: वेक्टर विज्ञप्ति स्मृति है कि यह आवंटित ठीक है। यदि आप पॉइंटर्स संग्रहीत कर रहे हैं, तो वे हटाए नहीं जाएंगे।
  3. वेक्टर किसी भी अन्य चर के रूप में बनाए जाते हैं, वे केवल ढेर में नहीं हैं क्योंकि वे वैक्टर हैं।
4

हाँ आप अपने बाद साफ करने के लिए वैक्टरों पर भरोसा कर सकते हैं।

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

उदाहरण के लिए, क्या आप इस तरह कुछ wonky ताला वस्तु का एक वेक्टर अगर:

class CLock 
    { 
    public: 
     CLock() {} 
     ~CLock() {} 

     void Lock(...) {...} 

     void Unlock(...) {...} 
    }; 

    std::vector<CLock> myLockVec; 

कैसे घड़ी की पता है की अपने वेक्टर सब कुछ जब इसकी किया अनलॉक करने के लिए चाहते हैं? वेक्टर के बारे में जानने के लिए वेक्टर नहीं बनाया गया है।

यह अनिवार्य रूप से संकेत का एक वेक्टर होने के रूप में एक ही स्थिति है:

std::vector<int*> myIntVec; 

कैसे वेक्टर पता है जो यहाँ सूचक मात्र हटा दिया गया है और NULL'd लगे और कौन से वास्तव में देखते हैं करता है? हो सकता है कि कुछ हटा दिए गए हैं और आपके विशेष मूल्य 0xdeadbeef पर सेट हैं, जिसका अर्थ हटा दिया गया है।

बिंदु यह है कि वेक्टर के पास इसका कोई मतलब नहीं है या पता है कि इसके तत्व पॉइंटर्स या ताले या जो कुछ भी हैं। उन्हें केवल उन चीजों की आवश्यकता होती है जिनके पास डिफॉल्ट कन्स्ट्रक्टर होते हैं और कॉपी करने योग्य होते हैं, और वेक्टरों के अन्य तत्वों को पूरा करते हैं।

समाधान यह सुनिश्चित करना है कि जो भी वेक्टर होल्ड को इसकी सफाई के लिए ज़िम्मेदार होना चाहिए। इसे RAII कहा जाता है - संसाधन आवंटन प्रारंभ है, अधिक महत्वपूर्ण बात यह है कि संसाधन विनाश डीलोकेशन है। ऊपर हमारे क्लॉक उदाहरण के साथ, जवाब स्पष्ट है, जब हम कर लें तो अनलॉक करना सुनिश्चित करें!

class CLock 
{ 
     ... 
     ~Clock() 
     { 
      if (locked) 
      { 
       Unlock(); 
      } 
     } 
} 

लेकिन पॉइंटर्स के साथ यह इतना स्पष्ट नहीं है। समाधान पॉइंटर को smart_ptr क्लास में लपेटना है। इनमें से सबसे अधिक प्रभाव boost family of smart poniters हैं।

class CSmartPointer<T> 
{ 
     CSmartPointer(T* rawPtr) 
     { 
     m_ptr = rawPtr; 
     } 

     ~CSmartPointer() 
     { 
     delete m_ptr; 
     } 
} 

अतिरिक्त सुविधाओं में इस तरह के संदर्भ गिनती के रूप में संकेत के साथ खेलने में लाया जाता है, लेकिन ऊपर के उदाहरण आप समस्या की प्रकृति का सार देना चाहिए और कैसे अपने आम तौर पर हल किया।

1

"खोई गई स्मृति" के लिए, @RichieHindie क्या कहता है।

दूसरे प्रश्न के लिए:

नई कीवर्ड के बिना बनाया वैक्टर वास्तव में उनके अपने उपकरणों के छोड़ा जा सकता है और खुद के बाद स्पष्ट करने के लिए पर भरोसा किया है, भले ही कोड मध्य प्रवाह

निरस्त किया गया है

सामान्य प्रोग्राम समाप्ति (अपवाद द्वारा समाप्ति सहित) यह सुनिश्चित करता है कि विनाशक निष्पादित करें (स्थिर डेटा के लिए उन लोगों के बारे में कुछ प्रश्नोत्तरी के साथ - सिद्धांत में उनको भी चलना चाहिए, अभ्यास में आपको कभी-कभी समस्याएं मिल सकती हैं), पी की पर्याप्त हार्ड क्रैश रोकेस किसी भी व्यवहार की गारंटी नहीं दे सकता - उदाहरण के लिए, kill -9 गारंटी देता है ताकि आप अपने प्रोग्राम ASAP को समाप्त कर सकें, बिना किसी विनाशक या किसी और को निष्पादित करने का मौका दिए।

+0

अनचाहे अपवाद (जो रनटाइम को अंततः समाप्त करने के लिए कॉल करते हैं()) विनाशकों को निष्पादित नहीं कर सकते हैं। इस मामले में अवांछित व्यवहार ढेर कार्यान्वयन-परिभाषित है। – ASk

8

वैक्टर बनाने के लिए new का उपयोग न करें। बस उन्हें ढेर पर रखो।

वेक्टर का विनाशक वेक्टर में प्रत्येक तत्व के विनाशक को स्वचालित रूप से आमंत्रित करता है। इसलिए आपको ऑब्जेक्ट्स को हटाने के बारे में चिंता करने की ज़रूरत नहीं है। हालांकि, यदि आपके पास पॉइंटर्स का वेक्टर है, तो ऑब्जेक्ट्स जो पॉइंटर्स संदर्भित करते हैं साफ़ नहीं होंगे। यहां कुछ उदाहरण कोड है। स्पष्टता के लिए मैं अधिक जानकारी छोड़ रहा हूं:

class HeapInt 
{ 
    public: 
     HeapInt(int i) {ptr = new int(i);} 
     ~HeapInt() {delete ptr;} 
     int& get() {return *ptr;} 
    private: 
     int* ptr; 
}; 

int main() 
{ 
    // this code DOES NOT leak memory 
    std::vector<HeapInt> vec; 
    for (int i = 0; i < 10; ++i) 
    { 
     HeapInt h(i); 
     vec.push_back(h); 
    } 
    return 0; 
} 

भले ही मुख्य() अपवाद फेंकता है, कोई स्मृति गुम हो जाती है।

int main() 
{ 
    // this code though, DOES leak memory 
    std::vector<int*> vec; 
    for (int i = 0; i < 10; ++i) 
    { 
     int* ptr = new int(i); 
     vec.push_back(ptr); 
    } 
    // memory leak: we manually invoked new but did not manually invoke delete 
    return 0; 
} 
+0

यह हमेशा काम नहीं करता है। –

+4

हां, लेकिन सवाल पूछने वाला व्यक्ति स्पष्ट रूप से नहीं जानता कि वैक्टरों को आम तौर पर ढेर पर रखा जाना चाहिए। – rlbond

+0

दूसरा उदाहरण रिसाव स्मृति कैसे होगा? कार्यक्रम समाप्त होता है और ओएस स्मृति को पुनः प्राप्त करता है, या क्या मुझे मेमोरी प्रबंधन –

2

हम दोनों में से एक एक सा यहाँ उलझन में है: हालांकि, इस कोड रिसाव स्मृति करता है।

यदि आप std :: vector का उपयोग कर रहे हैं, तो आपको इसके तत्वों के लिए मैन्युअल रूप से स्मृति आवंटित करने की आवश्यकता नहीं है। जब भी आप push_back() करते हैं तो अतिरिक्त स्थान स्वचालित रूप से आवंटित किया जाएगा। अगर आपको किसी कारण से पहले से आवंटित सभी जगहों की आवश्यकता है, तो आप आरक्षित() को कॉल कर सकते हैं। किसी भी तरह से, जब वेक्टर नष्ट हो जाता है तो स्मृति आपके लिए स्वचालित रूप से मुक्त हो जाती है।

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

1

जब आप "नया" उपयोग करना चाहते हैं, तो इस संबंध में एक अन्य परिदृश्य का उल्लेख नहीं किया गया है, कुछ मामलों में जब वेक्टर कक्षा का सदस्य चर होता है। एनयूएलएल को अतिरिक्त सेमफोर के रूप में इस्तेमाल किया जा सकता है, उदाहरण के लिए मांग पर निर्माण के दौरान; साथ ही, यदि वेक्टर का उपयोग आपकी कक्षा पर कम आबादी वाला है, तो तब तक एक भी निर्माण नहीं करना चाहिए जब तक कि इसकी वास्तव में आवश्यकता न हो, आपको सभी उदाहरणों पर अतिरिक्त 4 बाइट जुर्माना के साथ-साथ सूचक संकेत के रनटाइम पेनल्टी के खर्च पर स्मृति भी बचाएगी।

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