2008-11-11 8 views
7

अगर मैं निम्नलिखित कोड है,क्या myVector.erase (myPtr) myPtr द्वारा इंगित ऑब्जेक्ट को हटाता है?

Foo *f = new Foo(); 
vector<Foo*> vect; 
vect.push_back(f); 
// do stuff 
vect.erase(f); 

मैं एक स्मृति रिसाव में बनाया है? मुझे ऐसा लगता है, लेकिन शब्द मिटा देता है यह महसूस करता है कि यह इसे हटा रहा है।

यह लिखकर, मुझे आश्चर्य है कि एसटीएल वेक्टर में पॉइंटर डालने की कोई गलती नहीं है। तुम क्या सोचते हो?

उत्तर

8

हां, आपने उसमें एक स्मृति रिसाव बनाया है। std :: वेक्टर और अन्य कंटेनर सिर्फ पॉइंटर को हटा देंगे, वे सूचक पॉइंटर पॉइंट को मुक्त नहीं करेंगे।

मानक पुस्तकालय कंटेनर में पॉइंटर डालना असामान्य नहीं है। हालांकि, समस्या यह है कि कंटेनर से इसे हटाते समय आपको इसे हटाने का ट्रैक रखना होगा।

{ 
    boost::shared_ptr<foo> f(new foo); 

    std::vector< boost::shared_ptr<foo> > v; 
    v.push_back(f); 
    v.erase(v.begin()); 
} /* if the last copy of foo goes out of scope, the memory is automatically freed */ 

अगले सी ++ मानक (आमतौर पर सी ++ 1x और C++ 0x कहा जाता है) std::shared_ptr शामिल होंगे: एक बेहतर है, फिर भी आसान है, जिस तरह से ऊपर करने के लिए, को बढ़ावा देने :: shared_ptr उपयोग करने के लिए है। वहां, आप std::unique_ptr<T> का उपयोग करने में भी सक्षम होंगे जो तेज़ है, क्योंकि यह प्रतिलिपि बनाने की अनुमति नहीं देता है। सी ++ 0x में कंटेनर के साथ std::unique_ptr का उपयोग ptr_container लाइब्रेरी में बढ़ावा देने के समान है।

+0

बूस्ट :: shared_ptr का उपयोग करने के लिए बहुत सावधान रहें, क्योंकि यह उत्तर auto_ptr के बजाय, यह उत्तर निर्देश देता है। एसटीएल कंटेनरों का उपयोग auto_ptr के साथ बिल्कुल नहीं किया जा सकता है (कारण इस टिप्पणी में व्याख्या करने के लिए थोड़ा लंबा है)। – Gorpik

+0

ठीक है, मैं इस पर ध्यान देता हूं। धन्यवाद ! – Barth

1

निश्चित रूप से एक मानक कंटेनर में पॉइंटर को इंगित करने की गलती नहीं है (हालांकि यह auto_ptr का कंटेनर बनाने की गलती है)। हां, आपको व्यक्तिगत तत्वों द्वारा इंगित स्मृति को मुक्त करने के लिए स्पष्ट रूप से हटाने की आवश्यकता है, या आप smart pointers को बढ़ावा देने में से एक का उपयोग कर सकते हैं।

4

दूसरा विकल्प बूस्ट Pointer Containers का उपयोग करना है। वे वही करने के लिए डिज़ाइन किए गए हैं जो आप चाहते हैं।

2

वैकल्पिक रूप से boost :: ptr_vector container है।

यह जानता है कि यह पॉइंटर्स धारण कर रहा है कि इसका स्वामित्व है और इस प्रकार ऑटो उन्हें हटा देता है।

एक अच्छी तरफ प्रभाव के रूप में, तत्वों तक पहुंचने पर यह ऑब्जेक्ट का संदर्भ देता है कि कोड को अच्छा दिखने के लिए सूचक नहीं है।

Foo *f = new Foo(); 
boost::ptr_vector<Foo> vect; 
vect.push_back(f); 
// do stuff 
vect.erase(f); 
+0

महान संदर्भ, इसके लिए धन्यवाद। ऐसा ही होता है कि मैं पिछले कुछ दिनों में कंटेनर-ऑफ-पीटीआरएस डेटा संरचनाओं को दोबारा बेचता हूं, बूस्ट :: अप्रत्यक्ष_इटरेटर सहायक रहा है लेकिन इन ptr_xxx कंटेनर मुझे भी बेहतर लगेगा ... शायद मुझे फिर से प्रतिक्रिया करने की आवश्यकता होगी;) – Roel

1

वेक्टर इसमें मौजूद डेटा को हटा देता है। चूंकि आपके वेक्टर में पॉइंटर्स होते हैं, यह केवल पॉइंटर्स को हटा देता है, न कि वह डेटा जो वे इंगित कर सकते हैं या नहीं।

यह सी ++ में एक सुंदर सामान्य नियम है कि स्मृति जारी की गई है जहां इसे आवंटित किया गया था। वेक्टर ने जो भी पॉइंटर्स इंगित किया है उसे आवंटित नहीं किया है, इसलिए इसे इसे जारी नहीं करना चाहिए।

आपको शायद अपने वेक्टर में पॉइंटर्स को पहले स्थान पर स्टोर नहीं करना चाहिए। कई मामलों में, आप कुछ इस तरह के साथ बंद बेहतर होगा:

vector<Foo> vect; 
vect.push_back(Foo()); 
// do stuff 
vect.erase(f); 

बेशक यह मानता है कि फू copyable है, और इसकी प्रतिलिपि निर्माता भी महंगा नहीं है कि, लेकिन यह मेमोरी लीक से बचा जाता है, और आप डॉन फू ऑब्जेक्ट को मिटाना याद रखना नहीं है। एक और दृष्टिकोण स्मार्ट पॉइंटर्स (जैसे बूस्ट के साझा_पीटीआर) का उपयोग करना होगा, लेकिन आपको पॉइंटर सेमेन्टिक्स की आवश्यकता नहीं हो सकती है, इस मामले में सरल समाधान सबसे अच्छा है।

1

एसटीएल कंटेनर आपकी याददाश्त को मुक्त नहीं करेंगे।सबसे अच्छी सलाह स्मार्ट पॉइंटर्स का उपयोग कर रही है, यह जानकर कि std :: auto_ptr कंटेनरों के अंदर फिट नहीं होगा। मैं boost :: shared_ptr को बढ़ावा देने की सलाह दूंगा, या यदि आपके कंपाइलर विक्रेता को TR1 एक्सटेंशन (कई करते हैं) के लिए समर्थन है तो आप std :: tr1 :: shared_ptr का उपयोग कर सकते हैं।

यह भी ध्यान रखें कि वेक्टर पॉइंटर के लिए आरक्षित आंतरिक मेमोरी को भी मुक्त नहीं करेगा। std :: vectors कभी भी कॉल करने के लिए कॉल के साथ भी डाउनसाइज नहीं करते हैं()। यदि आपको एक वेक्टर को डाउनसाइज करने की आवश्यकता है तो आपको एक और वेक्टर बनाने और सामग्री को स्वैप करने का सहारा लेना होगा।

2

स्पष्ट क्यों सूचक को हटाया नहीं जाता है,

std::vector<char const*> strings; 
strings.push_back("hello"); 
strings.push_back("world"); 
// .erase should not call delete, pointers are to literals 

std::vector<int*> arrays; 
strings.push_back(new int[10]); 
strings.push_back(new int[20]); 
// .erase should call delete[] instead of delete 

std::vector<unsigned char*> raw; 
strings.push_back(malloc(1000)); 
strings.push_back(malloc(2000)); 
// .erase should call free() instead of delete 

सामान्य तौर पर, vector<T*>::erase पर विचार लगता है कि नहीं कर सकते कि आप एक T* के निपटान होता है।

+0

क्या विचार करें? कृपया हमें बताएं कि हमें क्या विचार करना चाहिए, भले ही केवल संक्षेप में। आप कुछ भी मिटाना प्रतीत नहीं कर रहे हैं, और आपके कोई भी धक्का किसी भी संदर्भ को साझा नहीं करता है। इसके बारे में कई मिनटों के बारे में सोचने के बाद, मैंने सोचा कि शायद आपका इरादा आपके 'char const *' के साथ इस मुद्दे को नोटिस करने के लिए था, लेकिन मुझे यकीन नहीं है कि आपका इरादा क्या है। कृपया हमें चट्टान-हैंगर से न छोड़ें। -1 यदि मैं आपके इरादे के बारे में सही था, तो "इस तरह के ऐसे मामले" के बारे में "क्या होगा" जोड़ना उपयोगी होगा। – Aaron

+0

@Aaron: इस बात पर विचार करें कि यह उपरोक्त उदाहरणों के अनुसार 'std :: vector :: मिटाएं (iter) 'को मिटाएं * iter' के लिए उपयुक्त होगा या नहीं। और उत्तर देने के लिए: नहीं। पहला उदाहरण स्ट्रिंग शाब्दिक (कुछ भी नहीं करना चाहिए) पर 'हटाएं' कहता है, दूसरे उदाहरण में 'मिटा' को 'हटाएं []' को कॉल करना होगा और तीसरे मामले में 'मिटा' होगा 'मुफ्त() 'कॉल करने की आवश्यकता है। – MSalters

+0

दाएं। मुझे शायद दूसरे नमूने (सरणी) के साथ समस्या को पकड़ा जाना चाहिए था; यकीन नहीं है कि मैंने क्यों नहीं किया। तीसरे व्यक्ति (मॉलोक) के लिए: मैं स्वीकार करूंगा कि यह बहुत लंबा रहा है क्योंकि मैंने किसी भी चीज़ के लिए मॉलोक का उपयोग किया है जिसे मैं भूल गया हूं कि आपको नया/मुफ्त या मॉलोक/डिलीट नहीं करना चाहिए। तीसरा नमूना विशेष रूप से आपको कम से कम एक पंक्ति या दो के साथ समझा जाना चाहिए; मेरे जैसे लोगों की वजह से। ;) -1 को हटा रहा है, और यदि आप उत्तर में अपनी टिप्पणी डालते हैं तो मैं इसे +1 भी दूंगा। – Aaron

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