2009-08-20 12 views
6

रनिंग वाल्ग्रिंड या शुद्धीकरण अगले चरण होगा, लेकिन कोड लिखते समय आप कैसे सुनिश्चित करेंगे कि इससे कोई मेमोरी लीक नहीं होगी? आप चीजों को निम्नलिखित सुनिश्चित कर सकते हैं: - 1: खोला फ़ाइल वर्णनकर्ता बंद कर दिया है या नहींयह कैसे सुनिश्चित करें कि सी ++ कोड लिखते समय यह किसी भी स्मृति रिसाव का कारण नहीं बनता है?

कुछ और किसी भी बात है: नई बराबर की संख्या 2 नष्ट करने के लिए?

+1

नई == विचार को नष्ट के साथ सावधान। मान लीजिए कि आपके पास कई जगहें हैं जहां स्मृति जारी की जा सकती है, प्रत्येक को शून्य के लिए चेक के साथ i'e.' अगर (पी) पी हटाएं; 'आप नए == एन * हटा सकते हैं जहां एन मनमानी है। – ezpz

+3

'हटाएं 0' एक नो-ऑप है, इसलिए आपको यह जांचना नहीं चाहिए कि आपका पॉइंटर इसे हटाने से पहले शून्य है या नहीं। –

+0

धन्यवाद पीटर! यह मेरा नंबर 1 पालतू शिखर है! "अगर (पी) पी हटा दें;" इस रूप में फिर से लिखा जाना चाहिए: "पी हटाएं; पी = 0;" या कुछ समान है। – Thomi

उत्तर

25

RAII मुहावरा का प्रयोग हर जगह आप कर सकते हैं

उपयोग स्मार्ट संकेत दिए गए हैं, उदा std :: auto_ptr जहां उचित हो। (यह रूप में मानक संग्रह में से किसी में auto_prt का उपयोग नहीं करते काम नहीं करेगा के रूप में आपको लगता है कि यह होगा)

+1

+1। लेकिन क्यों 'हर जगह आप कर सकते हैं' और हमेशा नहीं (स्मार्ट पॉइंटर्स को आरएआईआई के रूप में देखते हुए)? –

+2

@orsogufo, मुझे पूर्ण बयान पसंद नहीं है। अगर मैंने कहा "हमेशा" कोई ऐसी स्थिति के साथ आ सकता है जहां आरएआईआई उचित नहीं है (सिर्फ इसलिए कि मैंने ऐसी स्थिति के बारे में सोचा नहीं है इसका मतलब यह नहीं है कि किसी और के पास नहीं है)। – Glen

+0

हां। यदि आप बिना स्मार्ट पॉइंटर्स के नए और हटा रहे हैं तो आप कुछ गलत कर रहे हैं। – Thomi

7
+0

अच्छी पहली सलाह है, लेकिन मंडलियों – gimpf

+2

पर विफल रहता है हां, दूसरी सलाह "स्वयं स्मार्ट बनें" होना चाहिए :) – Aamir

+2

संदर्भ ग्राफ में चक्रों को हल करने के लिए boost :: weak_ptr <> का उपयोग करें। – janm

0

यकीन है कि साझा अपने आवेदन के द्वारा बनाई गई स्मृति बनाओ अगर कोई भी इसे अब और उपयोग कर रहा है मुक्त हो जाता है, साफ मेमोरी मैप की गई फाइलें ...

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

1

मैं हमेशा std::auto_ptr का उपयोग करता हूं जब मुझे ढेर पर एक नई वस्तु बनाने की आवश्यकता होती है।

std::auto_ptr<Foo> CreateFoo() 
{ 
    return std::auto_ptr<Foo>(new Foo()); 
} 

भले ही आप

CreateFoo() 

फोन यह

+0

सिवाय इसके कि एक std :: auto_ptr कॉपी नहीं किया जा सकता है। इसका मतलब यह है कि इसे अन्य चीजों के साथ मानक कंटेनर में नहीं रखा जा सकता है। –

+0

यह निश्चित रूप से कॉपी किया जा सकता है, अन्यथा आप ऐसे कार्यों को लिखने में सक्षम नहीं होंगे जो auto_ptrs लौटाते हैं। –

0

लीक नहीं होगा अगर आप अपने डेटा संरचना शायद अपनी स्मृति के सभी खाने के लिए अपने कोड में रिकर्सिवली किसी भी पेड़ या ग्राफ बनाते हैं।

14

जहां भी संभव हो गतिशील रूप से वस्तुओं को बनाने से बचें। जावा और अन्य समान भाषाओं से आ रही प्रोग्रामर्स अक्सर लिखने सामान की तरह:

string * s = new string("hello world"); 

जब वे लिखा जाना चाहिए था:

string s = "hello world"; 

इसी तरह, वे संकेत का संग्रह बना जब वे मूल्यों के संग्रह बनाने चाहिए। उदाहरण के लिए, अगर आप इस तरह एक वर्ग है, तो:

class Person { 
    public: 
     Person(const string & name) : mName(name) {} 
     ... 
    private: 
     string mName; 
}; 

बल्कि तरह कोड लिखने की तुलना:

vector <Person *> vp; 

या यहाँ तक कि:

vector <shared_ptr <Person> > vp; 

बजाय का उपयोग मान:

vector <Person> vp; 

आप आसानी से ऐसे एवी में जोड़ सकते हैं ईक्टर:

vp.push_back(Person("neil butterworth")); 

और व्यक्ति और वेक्टर दोनों के लिए सभी मेमोरी आपके लिए प्रबंधित की जाती है।बेशक, यदि आपको पॉलिमॉर्फिक प्रकारों के संग्रह की आवश्यकता है, तो आपको (स्मार्ट) पॉइंटर्स का उपयोग करना चाहिए

+2

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

+1

क्या आपने मेरे उत्तर की अंतिम वाक्य पढ़ी? –

+1

या पहला, उस पर आओ - मैंने कहा "जहां संभव हो"। –

0

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

4

अपने डेटा को संग्रहीत करने के लिए एसटीएल कंटेनर का उपयोग कर नए को कॉल को कम करें।

1

बुनियादी कदम दुगना कर रहे हैं:

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

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

मुझे लगता है कि उन 2 मामलों में वे समय हैं जब आप स्मृति को रिसाव कर सकते हैं। यदि आप केवल स्मार्ट पॉइंटर का उपयोग सीधे करते हैं - कभी भी अपने आंतरिक डेटा को उजागर करने की इजाजत नहीं देते हैं, तो आप बाद के मुद्दे से सुरक्षित हैं। यदि आप अपना पूरा कोड लपेटते हैं जो नए का उपयोग करता है और कक्षा में हटा देता है (यानी आरएआईआई का उपयोग करके) तो आप भी पूर्व से बहुत सुरक्षित हैं।

यदि आप ऊपर करते हैं तो सी ++ में मेमोरी लीक से बचना बहुत आसान है।

5
  1. आरए II उपयोग
  2. छिपाएं डिफ़ॉल्ट प्रतिलिपि ctors, ऑपरेटर =() हर वर्ग में , जब तक कि एक) अपनी कक्षा तुच्छ है और केवल देशी प्रकार का उपयोग करता है और आप जानते हैं आईटी हमेशा इतनी ख किया जाएगा) आप स्पष्ट रूप से अपने खुद के

1 पर) आरए II परिभाषित , विचार तो आप "मैंने कहीं हटाना कॉल करने के लिए याद करने की आवश्यकता होगी, मैं सिर्फ नए बुलाया" हटाए गए को अपने आप ही हो, यदि आप पाते हैं अपने आप को सोच है कुछ गलत कर रहा हूँ। डिलीट या तो होना चाहिए) स्वचालित या बी) एक डीटीआर में डाला जाना चाहिए (और कौन सा डीटीआर स्पष्ट होना चाहिए)।

2) छुपाएं डिफ़ॉल्ट। नकली डिफ़ॉल्ट प्रतिलिपि ctors आदि की पहचान करना एक दुःस्वप्न हो सकता है, सबसे आसान बात उन्हें छिपाने से बचाना है। यदि आपके पास सामान्य "रूट" ऑब्जेक्ट है जो सबकुछ प्राप्त होता है (किसी भी तरह से डीबगिंग/प्रोफाइलिंग के लिए आसान हो सकता है) तो यहां डिफ़ॉल्ट को छुपाएं, फिर जब कोई कुछ विरासत कक्षा को संकलित करने/प्रतिलिपि बनाने की कोशिश करता है तो ctor's आदि नहीं हैं बेस क्लास पर उपलब्ध है। अंगूठे का

+2

boost :: noncopyable # 2 – jalf

+0

@jalf के लिए बहुत आसान है: धन्यवाद, अगर मुझे हर किसी को गंभीर C++ फिर से करने की आवश्यकता है तो बढ़ावा मिलेगा। 5 साल या उससे अधिक समय में क्रोध में सी ++ का उपयोग नहीं किया है :) –

+0

उपरोक्त, लेकिन क्यों छुपा ऑपरेटर *()? –

1

दो सरल नियमों:

  • कभी स्पष्ट रूप से delete फोन (एक आरए II कक्षा के बाहर, कि है)। प्रत्येक स्मृति आवंटन RAII वर्ग की ज़िम्मेदारी होना चाहिए जो विनाशक में हटा देता है।
  • लगभग स्पष्ट रूप से new पर कॉल न करें।यदि आप करते हैं, तो आपको तुरंत पॉइंटर को एक स्मार्ट पॉइंटर में लपेटना चाहिए, जो आवंटन का स्वामित्व लेता है, और ऊपर जैसा काम करता है।

अपनी खुद की आरए II कक्षाओं में, दो आम नुकसान कर रहे हैं:

  • विफलता सही ढंग से कॉपी करने को संभालने के लिए: कौन स्मृति के स्वामित्व लेता है, तो वस्तु की नकल की है? क्या वे एक नया आवंटन करते हैं? क्या आप कॉपी कॉपी कन्स्ट्रक्टर और असाइनमेंट ऑपरेटर दोनों को लागू करते हैं? क्या बाद में स्वयं असाइनमेंट संभालता है?
  • अपवाद सुरक्षा पर विचार करने में विफलता। क्या होता है यदि किसी ऑपरेशन के दौरान अपवाद फेंक दिया जाता है (उदाहरण के लिए असाइनमेंट)? क्या वस्तु एक सतत स्थिति में वापस आती है? (यह हमेशा करना चाहिए, इससे कोई फर्क नहीं पड़ता) क्या यह ऑपरेशन से पहले राज्य में वापस आ जाता है? (यह संभव होने पर ऐसा करना चाहिए) std::vector उदाहरण के लिए push_back के दौरान इसे संभालना होगा। इससे वेक्टर का आकार बदल सकता है, जिसका अर्थ है 1) एक मेमोरी आवंटन जो फेंक सकता है, और 2) सभी मौजूदा तत्वों की प्रतिलिपि बनाई जानी चाहिए, जिनमें से प्रत्येक फेंक सकता है। std::sort जैसे एक एल्गोरिदम को भी इससे निपटना होगा। इसे उपयोगकर्ता द्वारा आपूर्ति किए गए तुलनाकर्ता को कॉल करना है, जो संभावित रूप से भी फेंक सकता है! यदि ऐसा होता है, तो अनुक्रम एक वैध स्थिति में छोड़ा गया है? क्या अस्थायी वस्तुओं को साफ तरीके से नष्ट कर दिया गया है?

यदि आप अपने आरएआईआई कक्षाओं में उपरोक्त दो मामलों को संभालते हैं, तो उनके लिए स्मृति को रिसाव करना बहुत असंभव है। और अगर आप आरए II कक्षाओं का उपयोग सभी संसाधन आवंटन (स्मृति आवंटन, फ़ाइल हैंडल, डेटाबेस कनेक्शन और संसाधन है कि हासिल कर लिया और जारी होने की किसी भी अन्य प्रकार) रैप करने के लिए है, तो अपने आवेदन स्मृति लीक नहीं कर सकते हैं।

+0

इन कक्षाओं के निर्माण के दौरान मानक और बूस्ट स्मार्ट पॉइंटर्स का उपयोग करें। यह आपको काम और सूक्ष्म बग बचाएगा। –

+1

बेशक। जब आपको आवश्यकतानुसार मानक उपकरण उपलब्ध होते हैं, * * उनका उपयोग करें। लेकिन मैं अभी भी तर्क दूंगा कि इन सूक्ष्म समस्याओं के बारे में जागरूक होना महत्वपूर्ण है। – jalf

3

मैं ग्लेन और jalf हर मौके पर आरए II के बारे में के साथ कर रहा हूँ।

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

मैं लंबे समय से आयोजित किया है कि स्पष्ट "हटाएँ" स्मृति प्रबंधन क्या "गोटो" प्रवाह नियंत्रण करने के लिए है के लिए है। this answer में इस पर और अधिक।

+0

मैं नए के लिए बहुत कुछ कहूंगा। कई संसाधनों के लिए, मैं एक पूर्ण आरएआईआई कक्षा लिखना पसंद करता हूं जो संसाधन बनाता है और इसे रिलीज़ करता है। एक स्मार्ट सूचक केवल हटाने के लिए ज़िम्मेदार होता है, इसलिए इसे संसाधन को कहीं और बनाने की आवश्यकता होती है, जो थोड़ा सा त्रुटि-प्रवण होता है। – jalf

+0

दिलचस्प। मुझे पहले पुराने कोड पर "पुर्ज हटाएं" से अच्छे नतीजे मिले हैं, लेकिन इसे कभी भी नए पर विस्तारित नहीं माना जाता है, शायद इसलिए कि मैं मूल रूप से सी ++ कोड बनाने के दृष्टिकोण से इसे "जावा जैसी" बनाने के दृष्टिकोण से आ रहा था। । संदिग्ध सी ++ 0x के विविध टेम्पलेट्स स्मार्ट पॉइंटर प्रकारों में कन्स्ट्रक्टर तर्कों को पार करना आसान बनाने के लिए कहीं उपयोगी होंगे जो नए आविष्कार के लिए भी जिम्मेदार होंगे। – timday

+1

बूस्ट में बूस्ट :: मेक_श्रेड सुविधा है जो प्रकार के निर्माता में उत्तीर्ण तर्कों को अग्रेषित करके आपके लिए boost :: shared_ptr बनाती है: 'boost :: shared_ptr ptr = make_shared (Arg1, Arg2, ... ' –

0

समाविष्ट valgrind इकाई और जल्दी अपने विकास चक्र में और यह consistantly का उपयोग प्रणाली का परीक्षण।

+1

यह अब तक बेहतर है कि स्मृति प्रबंधन के मुद्दों के साथ शुरूआत न हो। –

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