यह सुनिश्चित करने के लिए कि मैं सी ++ कार्यक्रमों में मेमोरी लीक नहीं करता हूं, कुछ सामान्य युक्तियां क्या हैं? मैं यह कैसे पता लगाऊं कि गतिशील रूप से आवंटित की गई मेमोरी को कौन मुक्त करे?
यह सुनिश्चित करने के लिए कि मैं सी ++ कार्यक्रमों में मेमोरी लीक नहीं करता हूं, कुछ सामान्य युक्तियां क्या हैं? मैं यह कैसे पता लगाऊं कि गतिशील रूप से आवंटित की गई मेमोरी को कौन मुक्त करे?
जवाबों:
मेमोरी को मैन्युअल रूप से प्रबंधित करने के बजाय, जहां लागू हो, स्मार्ट पॉइंटर्स का उपयोग करने का प्रयास करें। बूस्ट लीब , टीआर 1 , और स्मार्ट पॉइंटर्स
पर एक नज़र डालें ।
इसके अलावा स्मार्ट पॉइंटर्स अब C ++ मानक का एक हिस्सा हैं जिन्हें C ++ 11 कहा जाता है ।
मैं पूरी तरह से RAII और स्मार्ट पॉइंटर्स के बारे में सभी सलाह का समर्थन करता हूं, लेकिन मैं थोड़ा उच्च-स्तरीय टिप भी जोड़ना चाहता हूं: प्रबंधन करने के लिए सबसे आसान मेमोरी वह मेमोरी है जिसे आपने कभी आवंटित नहीं किया है। सी # और जावा जैसी भाषाओं के विपरीत, जहां बहुत कुछ सब कुछ एक संदर्भ है, सी ++ में आपको जब भी आप स्टैक पर ऑब्जेक्ट डाल सकते हैं। जैसा कि मैंने कई लोगों (डॉ। स्ट्रॉस्ट्रुप सहित) को बताया है, मुख्य कारण है कि कचरा संग्रह कभी भी C ++ में लोकप्रिय नहीं हुआ है, यह अच्छी तरह से लिखा C ++ पहले स्थान पर बहुत अधिक कचरा पैदा नहीं करता है।
मत लिखो
Object* x = new Object;
या और भी
shared_ptr<Object> x(new Object);
जब आप बस लिख सकते हैं
Object x;
यह पोस्ट दोहरावदार लगती है, लेकिन C ++ में, जानने के लिए सबसे बुनियादी पैटर्न RAII है ।
बूस्टर, TR1 या यहां तक कि नीच (लेकिन अक्सर पर्याप्त कुशल) auto_ptr (लेकिन आपको इसकी सीमाओं को जानना चाहिए) दोनों से स्मार्ट पॉइंटर्स का उपयोग करना सीखें।
RAII C ++ में अपवाद सुरक्षा और संसाधन निपटान दोनों का आधार है, और कोई अन्य पैटर्न (सैंडविच, आदि) आपको दोनों (और अधिकांश समय, यह आपको कोई नहीं देगा) देगा।
RAII और गैर RAII कोड की तुलना नीचे देखें:
void doSandwich()
{
T * p = new T() ;
// do something with p
delete p ; // leak if the p processing throws or return
}
void doRAIIDynamic()
{
std::auto_ptr<T> p(new T()) ; // you can use other smart pointers, too
// do something with p
// WON'T EVER LEAK, even in case of exceptions, returns, breaks, etc.
}
void doRAIIStatic()
{
T p ;
// do something with p
// WON'T EVER LEAK, even in case of exceptions, returns, breaks, etc.
}
संक्षेप में कहने के लिए ( ओगरे भजन 33 से टिप्पणी के बाद ), आरएआईआई तीन अवधारणाओं पर निर्भर करता है:
इसका मतलब यह है कि सही C ++ कोड में, अधिकांश ऑब्जेक्ट के साथ निर्माण नहीं किया new
जाएगा, और इसके बजाय स्टैक पर घोषित किया जाएगा। और उन लोगों के लिए प्रयोग कर बनाया new
, सभी किसी न किसी तरह हो जाएगा scoped (जैसे कि स्मार्ट पॉइंटर से जुड़ा हुआ)।
एक डेवलपर के रूप में, यह वास्तव में बहुत शक्तिशाली है क्योंकि आपको मैन्युअल संसाधन हैंडलिंग (जैसा कि सी में किया गया है, या जावा में कुछ वस्तुओं के लिए जो उस मामले के लिए try
/ का गहन उपयोग finally
करता है) की देखभाल करने की आवश्यकता नहीं होगी ...
"scoped ऑब्जेक्ट ... नष्ट हो जाएगा ... कोई बात नहीं निकास" यह पूरी तरह से सच नहीं है। RAII को धोखा देने के तरीके हैं। किसी भी स्वाद की समाप्ति () सफाई को बायपास करेगी। बाहर निकलें (EXIT_SUCCESS) इस संबंध में एक ऑक्सीमोरोन है।
विल्हेमटेल उस बारे में काफी सही है: असाधारण हैं RAII को धोखा देने के लिए तरीके , जो सभी प्रक्रिया को रोकते हैं।
वे असाधारण तरीके हैं क्योंकि C ++ कोड को समाप्त, बाहर निकलने, आदि के साथ जोड़ा नहीं गया है, या अपवादों के मामले में, हम एक अखंड अपवाद चाहते हैं प्रक्रिया को क्रैश करने के लिए और कोर अपनी मेमोरी छवि को डंप करते हैं, और सफाई के बाद नहीं।
लेकिन हमें अभी भी उन मामलों के बारे में पता होना चाहिए, क्योंकि वे शायद ही कभी होते हैं, फिर भी वे हो सकते हैं।
(जो कॉल करता है terminate
या exit
कैज़ुअल सी ++ कोड में? ... मुझे याद है कि ग्लूट के साथ खेलते समय मुझे उस समस्या से जूझना पड़ता है : यह लाइब्रेरी बहुत सी-ओरिएंटेड है, जहाँ तक सी + + डेवलपर्स के लिए चीजों को मुश्किल बनाने के लिए इसे सक्रिय रूप से डिजाइन करना जैसे कि देखभाल नहीं स्टैक आवंटित डेटा के बारे में , या उनके मुख्य लूप से कभी नहीं लौटने के बारे में "दिलचस्प" निर्णय लेने के बारे में ... मैं उस बारे में कोई टिप्पणी नहीं करूंगा) ।
आप स्मार्ट पॉइंटर्स को देखना चाहेंगे, जैसे कि बूस्ट के स्मार्ट पॉइंटर्स ।
के बजाय
int main()
{
Object* obj = new Object();
//...
delete obj;
}
बूस्ट :: share_ptr संदर्भ संख्या शून्य होने के बाद स्वचालित रूप से हटा देगा:
int main()
{
boost::shared_ptr<Object> obj(new Object());
//...
// destructor destroys when reference count is zero
}
मेरा अंतिम नोट नोट करें, "जब संदर्भ गणना शून्य है, जो सबसे ठंडा हिस्सा है। इसलिए यदि आपके पास आपके ऑब्जेक्ट के कई उपयोगकर्ता हैं, तो आपको इस बात का ध्यान नहीं रखना होगा कि ऑब्जेक्ट अभी भी उपयोग में है। एक बार कोई भी आपके लिए संदर्भित नहीं होता है। साझा सूचक, यह नष्ट हो जाता है।
यह एक रामबाण दवा नहीं है। हालांकि आप आधार पॉइंटर तक पहुंच सकते हैं, लेकिन जब तक आप यह नहीं कर रहे थे कि आप आश्वस्त नहीं थे, तब तक आप इसे तीसरी पार्टी एपीआई में नहीं भेजना चाहते। बहुत बार, आपके "पोस्टिंग" सामान को किसी अन्य थ्रेड के लिए काम करने के लिए बनाया जा सकता है, जिससे कार्यक्षेत्र समाप्त हो जाता है। यह Win32 में PostThreadMessage के साथ आम है:
void foo()
{
boost::shared_ptr<Object> obj(new Object());
// Simplified here
PostThreadMessage(...., (LPARAM)ob.get());
// Destructor destroys! pointer sent to PostThreadMessage is invalid! Zohnoes!
}
हमेशा की तरह, किसी भी टूल के साथ अपनी सोच की टोपी का उपयोग करें ...
अधिकांश मेमोरी लीक ऑब्जेक्ट के स्वामित्व और जीवनकाल के बारे में स्पष्ट नहीं होने का परिणाम हैं।
पहली बात यह है कि जब भी आप कर सकते हैं स्टैक पर आवंटित करें। यह उन अधिकांश मामलों से संबंधित है जहां आपको किसी उद्देश्य के लिए एक ही वस्तु आवंटित करने की आवश्यकता होती है।
यदि आपको किसी वस्तु को 'नया ’करने की आवश्यकता है, तो अधिकांश समय उसके शेष जीवनकाल के लिए एक ही स्पष्ट स्वामी होगा। इस स्थिति के लिए मैं उन संग्रह टेम्प्लेट का एक गुच्छा उपयोग करने के लिए हूं, जो पॉइंटर द्वारा उन में संग्रहीत 'मालिक' वस्तुओं के लिए डिज़ाइन किए गए हैं। वे एसटीएल वेक्टर और मानचित्र कंटेनरों के साथ कार्यान्वित किए जाते हैं लेकिन कुछ अंतर हैं:
एसटीएल के साथ मेरा बीफ यह है कि यह वैल्यू ऑब्जेक्ट्स पर केंद्रित है, जबकि अधिकांश एप्लिकेशन में ऑब्जेक्ट्स अद्वितीय इकाइयाँ हैं जिनके पास उन कंटेनरों में उपयोग के लिए आवश्यक अर्थपूर्ण कॉपी शब्दार्थ नहीं हैं।
बाह, आप छोटे बच्चे और आपके नए-नए फालतू कूड़ा उठाने वाले ...
"स्वामित्व" पर बहुत मजबूत नियम - ऑब्जेक्ट को हटाने के लिए सॉफ़्टवेयर के किस ऑब्जेक्ट या भाग का अधिकार है। यदि कोई संकेतक "स्वामी" या "बस देखो, स्पर्श न करें" हो तो इसे स्पष्ट करने के लिए स्पष्ट टिप्पणियां और बुद्धिमान चर नाम। यह तय करने में मदद करने के लिए कि कौन मालिक है, हर सबरूटीन या विधि के भीतर जितना संभव हो उतना "सैंडविच" पैटर्न का पालन करें।
create a thing
use that thing
destroy that thing
कभी-कभी व्यापक रूप से विभिन्न स्थानों में बनाना और नष्ट करना आवश्यक होता है; मुझे लगता है कि से बचने के लिए मुश्किल है।
जटिल डेटा संरचनाओं की आवश्यकता वाले किसी भी कार्यक्रम में, मैं "ऑब्जेक्ट" पॉइंटर्स का उपयोग करके अन्य वस्तुओं वाले ऑब्जेक्ट्स का एक सख्त स्पष्ट-कट पेड़ बनाता हूं। यह पेड़ एप्लिकेशन डोमेन अवधारणाओं के मूल पदानुक्रम को दर्शाता है। उदाहरण 3 डी दृश्य वस्तुओं, रोशनी, बनावट का मालिक है। जब कार्यक्रम समाप्त होता है, तो रेंडरिंग के अंत में, सब कुछ नष्ट करने का एक स्पष्ट तरीका है।
कई अन्य बिंदुओं को तब भी परिभाषित किया जाता है जब भी एक इकाई को दूसरे तक पहुंच की आवश्यकता होती है, ताकि वह किरणों को स्कैन कर सके या जो भी हो; ये "बस देख रहे हैं" हैं। 3 डी दृश्य उदाहरण के लिए - एक ऑब्जेक्ट एक बनावट का उपयोग करता है लेकिन खुद का नहीं होता है; अन्य वस्तुएं उसी बनावट का उपयोग कर सकती हैं। किसी वस्तु का विनाश किसी भी बनावट के विनाश का आह्वान नहीं करता है ।
हाँ, यह समय लेने वाला है लेकिन मैं यही करता हूँ। मुझे शायद ही कभी स्मृति लीक या अन्य समस्याएं हैं। लेकिन फिर मैं उच्च-प्रदर्शन वैज्ञानिक, डेटा अधिग्रहण और ग्राफिक्स सॉफ्टवेयर के सीमित क्षेत्र में काम करता हूं। मैं अक्सर बैंकिंग और ईकॉमर्स, ईवेंट-चालित GUI या उच्च नेटवर्क वाली एसिंक्रोनस अराजकता जैसे लेन-देन नहीं करता। हो सकता है कि नए-नए तरीके से वहां फायदा हो!
बड़ा अच्छा सवाल!
यदि आप c ++ का उपयोग कर रहे हैं और आप रीयल-टाइम CPU-and-memory boud एप्लिकेशन (गेम्स की तरह) विकसित कर रहे हैं, तो आपको अपना मेमोरी मेमोरी मैनेजर लिखने की आवश्यकता है।
मुझे लगता है कि आप जो बेहतर कर सकते हैं वह विभिन्न लेखकों के कुछ दिलचस्प कार्यों को मर्ज करना है, मैं आपको कुछ संकेत दे सकता हूं:
फिक्स्ड साइज एलोकेटर की चर्चा हर जगह होती है, हर जगह नेट में
अलेक्जेंड्रेस्कु द्वारा 2001 में अपनी संपूर्ण पुस्तक "मॉडर्न सी ++ डिज़ाइन" में स्मॉल ऑब्जेक्ट अलोकेशन प्रस्तुत किया गया था
डिमेरिट लजारोव द्वारा लिखित गेम प्रोग्रामिंग जेम 7 (2008) "हाई परफॉर्मेंस हीप एलोकेटर" नाम के एक अद्भुत लेख में एक शानदार उन्नति पाई जा सकती है।
संसाधनों की एक महान सूची इस लेख में मिल सकती है
अपने आप से एक नॉब यूजफुल एलोकेटर लिखना शुरू न करें ... पहले खुद को डॉक्युमेंट करें।
C ++ में मेमोरी प्रबंधन के साथ लोकप्रिय एक तकनीक RAII है । मूल रूप से आप संसाधन आवंटन को संभालने के लिए कंस्ट्रक्टर / विध्वंसक का उपयोग करते हैं। बेशक अपवाद सुरक्षा के कारण C ++ में कुछ अन्य अप्रिय विवरण हैं, लेकिन मूल विचार बहुत सरल है।
मुद्दा आम तौर पर स्वामित्व में से एक में आता है। मैं आंद्रेई अलेक्जेंड्रेस्कु द्वारा स्कॉट मेयर्स और मॉडर्न सी ++ डिजाइन द्वारा प्रभावी सी ++ श्रृंखला पढ़ने की अत्यधिक सलाह देता हूं।
रिसाव न होने के बारे में पहले से ही बहुत कुछ है, लेकिन अगर आपको लीक पर नज़र रखने में मदद करने के लिए एक उपकरण की आवश्यकता है:
अपनी परियोजना में स्मृति स्वामित्व नियमों को साझा करें और जानें। COM नियमों का उपयोग करना सर्वोत्तम स्थिरता के लिए बनाता है ([में] पैरामीटर फोन करने वाले के स्वामित्व में होते हैं, कैली को कॉपी करना चाहिए; [आउट] कॉलर्स के स्वामित्व वाले हैं, एक संदर्भ रखते हुए कैली को कॉपी बनाना चाहिए; आदि;
valgrind रनटाइम में भी आपके प्रोग्राम मेमोरी लीकेज की जाँच करने के लिए एक अच्छा उपकरण है।
यह लिनक्स (एंड्रॉइड सहित) और डार्विन पर सबसे अधिक फ्लेवर पर उपलब्ध है।
यदि आप अपने कार्यक्रमों के लिए इकाई परीक्षण लिखने के लिए उपयोग करते हैं, तो आपको परीक्षणों पर व्यवस्थित चलने वाले सिस्टमग्रैटी की आदत डालनी चाहिए। यह संभावित रूप से प्रारंभिक चरण में कई मेमोरी लीक से बचाएगा। यह भी आम तौर पर उन्हें सरल परीक्षणों में इंगित करने के लिए आसान है कि एक पूर्ण सॉफ्टवेयर में।
बेशक यह सलाह किसी अन्य मेमोरी चेक टूल के लिए मान्य है।
यदि आप किसी चीज़ के लिए स्मार्ट पॉइंटर का उपयोग नहीं कर सकते / कर सकते हैं (हालाँकि यह बहुत बड़ा लाल झंडा होना चाहिए), तो अपने कोड में टाइप करें:
allocate
if allocation succeeded:
{ //scope)
deallocate()
}
यह स्पष्ट है, लेकिन यह सुनिश्चित करें कि आप किसी भी कोड को दायरे में टाइप करने से पहले उसे टाइप कर लें
इन बगों का एक लगातार स्रोत तब होता है जब आपके पास एक ऐसी विधि होती है जो किसी ऑब्जेक्ट के लिए एक संदर्भ या सूचक को स्वीकार करता है लेकिन स्वामित्व अस्पष्ट छोड़ देता है। शैली और टिप्पणी सम्मेलनों से इसकी संभावना कम हो सकती है।
ऐसा मामला होने दें जहां फ़ंक्शन ऑब्जेक्ट का स्वामित्व लेता है विशेष मामला। सभी स्थितियों में जहां ऐसा होता है, यह इंगित करने वाली हेडर फ़ाइल में फ़ंक्शन के बगल में एक टिप्पणी लिखना सुनिश्चित करें। आपको यह सुनिश्चित करने का प्रयास करना चाहिए कि ज्यादातर मामलों में मॉड्यूल या वर्ग जो किसी वस्तु को आवंटित करता है, उसे निपटाने के लिए भी जिम्मेदार है।
कास्ट का उपयोग करना कुछ मामलों में बहुत मदद कर सकता है। यदि कोई फ़ंक्शन किसी ऑब्जेक्ट को संशोधित नहीं करेगा, और इसके संदर्भ को संग्रहीत नहीं करता है जो रिटर्न होने के बाद बनी रहती है, तो एक संदर्भ को स्वीकार करें। कॉलर के कोड को पढ़ने से यह स्पष्ट होगा कि आपके फ़ंक्शन ने ऑब्जेक्ट के स्वामित्व को स्वीकार नहीं किया है। आपके पास एक ही फ़ंक्शन एक गैर-कॉन्स्टेंट पॉइंटर को स्वीकार कर सकता था, और कॉल करने वाले ने मान लिया हो सकता है कि कैली ने स्वामित्व स्वीकार नहीं किया है, लेकिन एक कास्ट संदर्भ के साथ कोई सवाल नहीं है।
तर्क सूचियों में गैर-कॉन्स्टेंस संदर्भों का उपयोग न करें। कॉलर कोड को पढ़ते समय यह बहुत स्पष्ट नहीं है कि कैलीले ने पैरामीटर का संदर्भ रखा हो सकता है।
मैं उन टिप्पणियों से असहमत हूं, जिन्होंने संदर्भ संख्याओं की सिफारिश की थी। यह आमतौर पर ठीक काम करता है, लेकिन जब आपके पास बग होता है और यह काम नहीं करता है, खासकर यदि आपका विध्वंसक गैर-तुच्छ कुछ करता है, जैसे कि एक मल्टीथ्रेडेड प्रोग्राम में। निश्चित रूप से अपने डिज़ाइन को समायोजित करने की कोशिश करें ताकि संदर्भ गिनती की आवश्यकता न हो अगर यह बहुत कठिन नहीं है।
महत्व के क्रम में युक्तियाँ:
-Tip # 1 अपने विध्वंसक "आभासी" घोषित करने के लिए हमेशा याद रखें।
-Tip # 2 RAII का उपयोग करें
-Tip # 3 बूस्ट के स्मार्ट पॉइंटर्स का उपयोग करें
-Tip # 4 अपने स्वयं के छोटी गाड़ी स्मार्टपॉइंट न लिखें, बूस्ट का उपयोग करें (अभी मैं जिस प्रोजेक्ट पर हूं, मैं उसका उपयोग नहीं कर सकता हूं, और मुझे अपने स्मार्ट पॉइंटर्स को डिबग करने का सामना करना पड़ा है, मैं निश्चित रूप से नहीं लूंगा एक ही मार्ग फिर से, लेकिन फिर फिर से अभी मैं हमारी निर्भरता को बढ़ावा नहीं दे सकता)
-Tip # 5 यदि इसके कुछ आकस्मिक / गैर-प्रदर्शन महत्वपूर्ण (हजारों वस्तुओं के साथ खेल में) काम थोरस्टेन ओटोसन के बूस्टर पॉइंटर कंटेनर में देखें
-Tip # 6 अपनी पसंद के प्लेटफ़ॉर्म के लिए लीक डिटेक्शन हेडर ढूंढें जैसे कि विज़ुअल लीक डिटेक्शन का "vld" हेडर
यदि आप कर सकते हैं, तो बूस्ट शेयर्ड_प्ट्र और मानक C ++ auto_ptr का उपयोग करें। वे स्वामित्व शब्दार्थ को व्यक्त करते हैं।
जब आप एक auto_ptr वापस करते हैं, तो आप कॉलर को बता रहे हैं कि आप उन्हें स्मृति का स्वामित्व दे रहे हैं।
जब आप एक share_ptr वापस करते हैं, तो आप कॉलर को बता रहे हैं कि आपके पास इसका संदर्भ है और वे स्वामित्व का हिस्सा लेते हैं, लेकिन यह केवल उनकी जिम्मेदारी नहीं है।
ये शब्दार्थ भी मापदंडों पर लागू होते हैं। यदि कॉलर आपको एक auto_ptr पास करता है, तो वे आपको स्वामित्व दे रहे हैं।
अन्य लोगों ने पहली बार (स्मार्ट पॉइंटर्स की तरह) मेमोरी लीक से बचने के तरीकों का उल्लेख किया है। लेकिन एक रूपरेखा और मेमोरी-विश्लेषण उपकरण अक्सर आपके पास एक बार मेमोरी समस्याओं को ट्रैक करने का एकमात्र तरीका होता है।
Valgrind memcheck एक उत्कृष्ट निःशुल्क है।
केवल MSVC के लिए, प्रत्येक .cpp फ़ाइल के शीर्ष पर निम्न जोड़ें:
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
फिर, जब वीएस 200 या उससे अधिक के साथ डिबगिंग होती है, तो आपको किसी भी लीक के बारे में बताया जाएगा जब आपका प्रोग्राम बाहर निकलता है (यह नया / हटाता है)। यह बुनियादी है, लेकिन इससे मुझे अतीत में मदद मिली है।
valgrind (केवल * निक्स प्लेटफॉर्म के लिए उपलब्ध) एक बहुत अच्छा मेमोरी चेकर है
यदि आप अपनी मेमोरी को मैन्युअल रूप से प्रबंधित करने जा रहे हैं, तो आपके पास दो मामले हैं:
यदि आपको इनमें से किसी भी नियम को तोड़ने की आवश्यकता है, तो कृपया इसे दस्तावेज़ित करें।
यह सूचक स्वामित्व के बारे में है।
आप मेमोरी आवंटन कार्यों को रोक सकते हैं और देख सकते हैं कि क्या प्रोग्राम से बाहर निकलने पर कुछ मेमोरी ज़ोन मुक्त नहीं हैं (हालांकि यह सभी अनुप्रयोगों के लिए उपयुक्त नहीं है )।
यह संचालकों के नए और हटाए जाने और अन्य मेमोरी आवंटन कार्यों को प्रतिस्थापित करके संकलन समय पर भी किया जा सकता है।
उदाहरण के लिए इस साइट में जाँच करें [C ++ में मेमोरी आवंटन डिबगिंग] नोट: डिलीट ऑपरेटर के लिए एक ट्रिक है, कुछ इस तरह से:
#define DEBUG_DELETE PrepareDelete(__LINE__,__FILE__); delete
#define delete DEBUG_DELETE
आप कुछ चर को फ़ाइल के नाम से संग्रहीत कर सकते हैं और जब ओवरलोड हटाए गए ऑपरेटर को पता चल जाएगा कि वह कौन सी जगह थी, जहां से इसे बुलाया गया था। इस तरह आप अपने प्रोग्राम से हर डिलीट और मॉलोक का पता लगा सकते हैं। मेमोरी चेकिंग सीक्वेंस के अंत में आपको यह रिपोर्ट करने में सक्षम होना चाहिए कि मेमोरी के आवंटित ब्लॉक को of डिलीट ’नहीं किया गया था, इसे फ़ाइल नाम और लाइन नंबर से पहचानना चाहिए जो मुझे लगता है कि आप क्या चाहते हैं।
तुम भी Visual Studio के तहत BoundsChecker की तरह कुछ कोशिश कर सकते हैं जो बहुत ही रोचक और उपयोग करने में आसान है।
हम अपने सभी आवंटन कार्यों को एक परत के साथ लपेटते हैं जो सामने एक संक्षिप्त स्ट्रिंग और अंत में एक प्रहरी झंडा लगाता है। इसलिए उदाहरण के लिए आपको "myalloc (pszSomeString, iSize, iAlignment); या नया (" विवरण ", iSize) MyObject () कॉल करना होगा, जो आंतरिक रूप से आपके हेडर और सेंटिनल के लिए निर्दिष्ट स्थान को पर्याप्त स्थान आवंटित करता है। , गैर-डिबग बिल्ड के लिए इसे बाहर टिप्पणी करना मत भूलना! यह ऐसा करने के लिए थोड़ी अधिक स्मृति लेता है, लेकिन लाभ लागत से बहुत दूर हैं।
इसके तीन लाभ हैं - पहला यह आपको आसानी से और जल्दी से ट्रैक करने की अनुमति देता है कि कोड क्या लीक कर रहा है, कुछ 'ज़ोन' में आवंटित कोड की त्वरित खोज करके लेकिन उन ज़ोन को मुक्त किया जाना चाहिए जब तक साफ नहीं किया जाता है। यह पता लगाने के लिए भी उपयोगी हो सकता है कि सभी प्रहरी सुनिश्चित करने के लिए जाँच करके एक सीमा को अधिलेखित कर दिया गया है। यह हमें कई बार बचाया है जब उन अच्छी तरह से छिपा दुर्घटनाओं या सरणी गलत खोजने की कोशिश कर रहा है। तीसरा लाभ यह है कि स्मृति के उपयोग को ट्रैक करने में यह देखने के लिए कि बड़े खिलाड़ी कौन हैं - एक मेमडंप में कुछ विवरणों का एक टकराव आपको बताता है कि 'ध्वनि' आपके लिए प्रत्याशित रूप से अधिक स्थान ले रही है, उदाहरण के लिए।
C ++ को RAII को ध्यान में रखकर बनाया गया है। स्मृति में C ++ का प्रबंधन करने का वास्तव में कोई बेहतर तरीका नहीं है। लेकिन सावधान रहें कि स्थानीय दायरे पर बहुत बड़ी मात्रा (जैसे बफर ऑब्जेक्ट) आवंटित न करें। यह स्टैक ओवरफ्लो का कारण बन सकता है और, यदि उस चंक का उपयोग करते समय सीमा की जाँच में कोई दोष है, तो आप अन्य चर या रिटर्न पतों को अधिलेखित कर सकते हैं, जो सभी प्रकार के सुरक्षा छेद की ओर जाता है।
विभिन्न स्थानों में आवंटित करने और नष्ट करने के बारे में एकमात्र उदाहरण धागा निर्माण (आपके द्वारा पारित पैरामीटर) है। लेकिन इस मामले में भी आसान है। यहाँ एक धागा बनाने का कार्य / विधि है:
struct myparams {
int x;
std::vector<double> z;
}
std::auto_ptr<myparams> param(new myparams(x, ...));
// Release the ownership in case thread creation is successfull
if (0 == pthread_create(&th, NULL, th_func, param.get()) param.release();
...
यहां थ्रेड फंक्शन के बजाय
extern "C" void* th_func(void* p) {
try {
std::auto_ptr<myparams> param((myparams*)p);
...
} catch(...) {
}
return 0;
}
बहुत आसान है ना? यदि थ्रेड निर्माण विफल हो जाता है, तो संसाधन auto_ptr द्वारा फ्री होल्ड (डिलीट) हो जाएगा, अन्यथा स्वामित्व थ्रेड को पास कर दिया जाएगा। क्या होगा यदि धागा इतना तेज है कि निर्माण के बाद यह थ्रेड से पहले संसाधन जारी करता है
param.release();
मुख्य कार्य / विधि में कहा जाता है? कुछ भी तो नहीं! क्योंकि हम सौदे को अनदेखा करने के लिए auto_ptr को 'बताएंगे'। क्या C ++ मेमोरी मैनेजमेंट आसान नहीं है? चीयर्स,
ईएमए!
स्मृति को उसी तरह प्रबंधित करें जैसे आप अन्य संसाधनों (हैंडल, फाइलें, डीबी कनेक्शन, सॉकेट ...) का प्रबंधन करते हैं। जीसी आपको उनके साथ मदद नहीं करेगा।
किसी भी फ़ंक्शन से सटीक एक वापसी। इस तरह से आप वहां पर डील-डौल कर सकते हैं और कभी नहीं चूक सकते।
अन्यथा गलती करना बहुत आसान है:
new a()
if (Bad()) {delete a; return;}
new b()
if (Bad()) {delete a; delete b; return;}
... // etc.