2010-01-06 18 views
6

मेरे पास abstractBase कक्षा और Derived कक्षा है।ऑपरेटर और सरणी हटाएं?

int main() 
{ 
    Base *arrayPtr[3]; 

    for (int i = 0; i < 3; i++) 
    { 
    arrayPtr[i] = new Derived(); 
    } 

    //some functions here 

    delete[] arrayPtr; 

    return 0; 
} 

मुझे यकीन नहीं है कि डिलीट ऑपरेटर का उपयोग कैसे करें। यदि मैं उपरोक्त दिखाए गए बेस क्लास पॉइंटर्स की सरणी हटा देता हूं, तो क्या यह कॉल क्लास ऑब्जेक्ट्स को नष्ट कर देगा और मेमोरी को साफ करेगा?

उत्तर

10

आप अपने सरणी के तत्वों, delete उनमें से प्रत्येक से अधिक पुनरावृति करना है। फिर delete [] को सरणी पर कॉल करें यदि इसे गतिशील रूप से new[] का उपयोग करके आवंटित किया गया है।

अपने नमूना कोड में, सरणी को स्टैक पर आवंटित किया जाता है ताकि आपको delete [] पर कॉल न करना पड़े।

यह भी सुनिश्चित करें कि आपके Base कक्षा में virtual विनाशक है।

संदर्भ: When should my destructor be virtual

+0

+1 सरणी पर [] को हटाने की आवश्यकता नहीं है, क्या यह 'नया' नहीं है। –

+7

के लिए – fretje

+0

हाँ जब आप अपनी टिप्पणी लिखते थे, तो मैं अपना जवाब संपादित कर रहा था, thx –

10

नहीं, आप स्पष्ट रूप से सरणी में प्रत्येक आइटम को हटाना होगा:

for (int i = 0; i < 3; ++i) 
{ 
    delete arrayPtr[i]; 
} 
+0

@Roger मुझे कोई डिलीट नहीं दिखता [] –

+0

@Roger: एहसास हुआ कि मेरी पहली पोस्ट के बाद ... पहले से ही संपादित किया गया था, लेकिन फिर भी धन्यवाद;) – fretje

+0

जेम्स: इसे पहले 5 मिनट के भीतर संपादित किया गया था। 'वर्चुअल' विनाशक बिंदु –

2

इसके बजाय आप क्या करना चाहिए:

for (int = i; i < 3; i++) 
{ 
    delete arrayPtr[i]; 
} 

और तुम delete[] arrayPtr; ऐसा नहीं करना चाहिए जैसा कि आप मुक्त करने के लिए कोशिश कर रहे हैं/एक ढेर arrayPtr आवंटित हटा दें।

विचार करने की एक और बात एक सरणी के बजाय पॉइंटर्स के std::vector का उपयोग कर रही है। और यदि आप एक कंपाइलर का उपयोग कर रहे हैं जो TR1 लागू करता है, तो आप कच्चे पॉइंटर्स के बजाय std::tr1::shared_ptr के std::vector का भी उपयोग कर सकते हैं, और आपको उन वस्तुओं को स्वयं हटाने के बारे में चिंता करने की आवश्यकता नहीं होगी।

उदाहरण:

{ 
    std::vector< std::tr1::shared_ptr<Base> > objects; 
    for (int i=0; i < 3; ++i) 
    { 
     objects.push_back(std::tr1::shared_ptr<Base>(new Derived())); 
    } 
} // here, once "objects" exit scope, all of your Derived objects are nicely deleted 
+0

Shared_ptr <> सब कुछ का जवाब नहीं है !!! पॉइंटर को शुरुआत के लिए साझा नहीं किया जाता है। boost :: ptr_vector <> एक बेहतर विकल्प हो सकता है। –

+0

सहमत हैं, बस "बुराइयों में से कम से कम" का सुझाव दे रहा था, इस अर्थ में, मैंने पहले से ही जीसीसी के साथ अपनी मैकबुक पर साझा_प्टर किया है, और बूस्ट :: ptr_vector का उपयोग करने के लिए मुझे परियोजना में बढ़ावा खींचने की आवश्यकता होगी, जो आवश्यक नहीं हो सकता है । – Dmitry

+0

@ मार्टिन यॉर्क: 'shared_ptr <>' * सब कुछ का जवाब नहीं है, लेकिन यह * अधिकांश पॉइंटर प्रश्नों के लिए एक सुरक्षित * उत्तर है। मैं आम तौर पर इसका उपयोग तब तक करता हूं जब तक मुझे कुछ अलग उपयोग करने का कोई कारण न हो, और सामान्य परिस्थितियों में इसका सुझाव देने में उचित रूप से आरामदायक हो। –

0

यकीन Base एक आभासी नाशक है बनाओ। फिर fretje outlined की तरह, सरणी में प्रत्येक तत्व को हटाएं, फिर सरणी हटाएं।

आपको सरणी के लिए std::vector का उपयोग करना चाहिए। उस ने कहा, आपको वास्तव में इस तरह की चीज़ के लिए बने कंटेनर का उपयोग करना चाहिए। (इसलिए आप सभी तत्वों को गलती से विफल नहीं करते हैं, जो निश्चित रूप से मामला होगा यदि कोई अपवाद फेंक दिया जाता है!) बूस्ट में such a library है।

+0

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

+0

ग्रेगरी: असहमत। किसी बिंदु पर आपको समझना चाहिए कि हुड (शायद) के तहत क्या चल रहा है, लेकिन यह अब मुझे स्पष्ट नहीं है कि यह किस क्रम में होना चाहिए (मैं आपके साथ सहमत था)। क्या आप समझ सकते हैं कि नया कॉल करने से पहले मैलोक कैसे काम करता है? क्या आपको समझना चाहिए कि गतिशील_कास्ट का उपयोग करने से पहले vtables कैसे काम करते हैं (और * फिर * पता लगाएं कि कार्यान्वयन का एक गारंटीकृत हिस्सा नहीं है)? दोनों नंबर उस ने कहा, आपको हमेशा यह जानना चाहिए कि आपको आवश्यक जानकारी को देखने के लिए कहां जाना है, या किससे बात करनी है, आदि –

+0

@ रोगर मुझे आपकी बात मिलती है। अपने उदाहरण लेते हुए, आपको ढेर स्मृति आवंटन के कार्यान्वयन विवरणों को जानने की आवश्यकता नहीं है, फिर भी ढेर और ढेर के बीच का अंतर जानना अच्छा होता है। आपको यह जानने की आवश्यकता नहीं है कि कैसे vtable कार्यान्वित किया जाता है और इस तरह, आपको अभी भी एक वर्चुअल विधि को कॉल करने के बारे में पता होना चाहिए। और अंत में एल्गोरिदम और डेटा संरचनाएं सोने हैं: आपको निश्चित रूप से एक एसडी :: वेक्टर या std :: सूची कार्यान्वयन का उपयोग कर रहे हैं, भले ही आप एक संगत सरणी और एक सूची अवधारणाओं के बीच अंतर जानना होगा; अन्यथा लंबे समय तक आपको सुराग की कमी है :) –

1

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

1

नहीं, आप ऐसा नहीं कर सकते हैं। जैसा कि अन्य ने सुझाव दिया है कि आपको प्रत्येक आइटम से गुज़रना होगा और इसे हटा देना होगा। यह याद रखने के लिए एक बहुत ही सरल नियम है। आप new का उपयोग कर आवंटित तो delete उपयोग करते हैं, और यदि आप new[] का इस्तेमाल किया था तो का उपयोग delete[]

0

नहीं, यह काफी आप क्या चाहते हैं नहीं करता है।

वहाँ दो अंक यहाँ के लिए बाहर देखने के लिए कर रहे हैं:

  1. वाक्य रचना अगर आप गतिशील सरणी आवंटित delete[] arrayPtr प्रयोग किया जाता है, इस तरह:

    arrayPtr = new (Base *)[mylength]; 
    

    अपने मामले में, तथापि, आप एक स्थाई आवंटित सरणी है, इसलिए इसे हटाने की कोई आवश्यकता नहीं है। हालांकि, आप सरणी में अलग-अलग तत्वों को हटाने की आवश्यकता है:

    class Base 
    { 
        virtual ~Base(); 
        /* ... */ 
    }; 
    

    :

    for (int = i; i < 3; i++) 
        delete arrayPtr[i]; 
    
  2. दूसरी बात आप देखभाल करने के लिए वर्ग के नाशक Base आभासी बनाने के लिए है की जरूरत है यह सुनिश्चित करता है कि जब आप Base * पर हटाते हैं जो वास्तव में Derived पर इंगित करता है, तो Derived के विनाशक को केवल Base का विनाशक कहा जाता है।

1

सूचना क्या अनुपस्थित है:

int main() { 
    boost::ptr_vector<Base> v; 
    for (int i = 0; i < 3; i++) v.push_back(new Derived()); 
    // some functions here, using v[0] through v[2] 
} 

चेक Boost's pointer containers बाहर।

1

ऑपरेटर हटाएं उस सूचक पर नए ऑपरेटर से मेल खाना चाहिए, अगर इसे new[] के साथ आवंटित किया गया था, तो आपको delete[] और इसके विपरीत कॉल करना होगा;

int* pInt = new int; 
delete pInt; OK 
delete [] pInt; WRONG 

int[] pIntArr = new int[3]; 
delete [] pIntArr; OK 
delete pIntArr; WRONG 

आपके मामले में वहाँ कुछ और गलत है - आप delete कि ढेर पर आवंटित किया गया था की कोशिश कर रहे हैं। वह काम नहीं करेगा।

आपको इस विशेष मामले में प्रत्येक सूचक को अलग-अलग हटा देना होगा।

1

आपके पास क्या है अपरिभाषित व्यवहार - एक बग। new पर प्रत्येक कॉल को delete से मिलान करने की आवश्यकता है; new[] पर प्रत्येक कॉल को delete[] से मिलान करने की आवश्यकता है। दोनों अलग हैं और मिश्रित नहीं किए जा सकते हैं।

आपके द्वारा पोस्ट किए गए कोड में, आपके पास स्टैक पर आवंटित बेस पर पॉइंटर्स की एक सरणी है। फिर आप स्टैक पर आवंटित सरणी पर delete[] पर कॉल कर रहे हैं - आप ऐसा नहीं कर सकते हैं। आप केवल delete[]new[] के साथ ढेर पर आवंटित एक सरणी कर सकते हैं।

आप प्रत्येक तत्व new साथ आवंटित के लिए delete के लिए एक कॉल की जरूरत है - या अधिमानतः, एक कंटेनर वर्ग, जैसे std::vector का उपयोग कर के बजाय एक सरणी का उपयोग कर इस पर गौर।

0

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

सरणी नए ऑपरेटर का उपयोग करने के लिए, अगर आप इस तरह की घोषणा करेंगे:

Base *array; 
array = new Base[3]; 
/* do stuff */ 
delete[] array; 

इस तीन वस्तुओं के लिए एक सन्निहित स्मृति क्षेत्र आवंटित - ध्यान दें कि आप बेस में ऑब्जेक्ट की श्रृंखला मिल गया है, नहीं बेस ऑब्जेक्ट्स के पॉइंटर्स की एक सरणी।

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