2010-05-11 21 views
32

निम्नलिखित कोड कोसाइडर करें:सी ++ पॉइंटर्स का ऐरे: हटाएं या हटाएं []?

class Foo 
{ 
    Monster* monsters[6]; 

    Foo() 
    { 
     for (int i = 0; i < 6; i++) 
     { 
      monsters[i] = new Monster(); 
     } 
    } 

    virtual ~Foo(); 
} 

सही विनाशक क्या है?

यह:

Foo::~Foo() 
{ 
    delete [] monsters; 
} 

या यह:

Foo::~Foo() 
{ 
    for (int i = 0; i < 6; i++) 
    { 
     delete monsters[i]; 
    } 
} 

वर्तमान में मेरे पास सबसे ऊपर का कन्स्ट्रक्टर है और सबकुछ ओकी काम कर रहा है, लेकिन निश्चित रूप से मैं नहीं देख सकता कि यह लीक होने वाला होता है ...

व्यक्तिगत रूप से, मुझे लगता है कि दूसरा संस्करण जो कुछ भी कर रहा हूं, उसके बारे में अधिक तर्कसंगत है। वैसे भी, ऐसा करने के लिए "उचित" तरीका क्या है?

उत्तर

36

delete[] monsters;

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

आपका अन्य कार्यान्वयन सही है क्योंकि सरणी में पॉइंटर्स गतिशील रूप से आवंटित Monster ऑब्जेक्ट्स को इंगित करते हैं।

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

+0

क्या आप कृपया थोड़ा सा समझा सकते हैं कि किसी को कॉपी कन्स्ट्रक्टर और कॉपी-असाइनमेंट ऑपरेटर को क्यों अक्षम करना चाहिए? – gen

+0

@gen यह एक अनुमान है, इसलिए इसे इसके लायक होने के लिए लें, लेकिन मैं * सोच रहा हूं कि कस्टम कॉपी असाइनमेंट/कन्स्ट्रक्टर के बिना निम्नलिखित हो सकता है: 2 पॉइंटर्स की एक राक्षस सरणी के साथ फू ऑब्जेक्ट्स जो इंगित करता है * वही * राक्षसों। यदि आप Foo2 में Foo1 को पॉइंटर्स को नष्ट कर देते हैं तो वे अमान्य हो जाएंगे क्योंकि वे जिस स्मृति को इंगित करते हैं उसे Foo1 द्वारा मुक्त किया गया है। – ZeroStatic

2

आपका दूसरा उदाहरण सही है; आपको monsters सरणी को ही हटाने की आवश्यकता नहीं है, केवल आपके द्वारा बनाई गई व्यक्तिगत वस्तुएं।

31

new के लिए आपको delete का उपयोग करना चाहिए। new[] के लिए delete[] का उपयोग करें। आपका दूसरा संस्करण सही है।

11

दूसरा परिस्थितियों में ठीक है (ठीक है, कम से कम गलत, वैसे भी)।

संपादित करें: "कम से कम गलत", मूल कोड में के रूप में पहली जगह में new या delete उपयोग करने के लिए कोई अच्छा कारण पता चलता है, तो आप शायद सिर्फ उपयोग करना चाहिए:

std::vector<Monster> monsters; 

परिणाम सरल हो जाएगा जिम्मेदारियों के कोड और क्लीनर अलगाव।

+1

कम से कम गलत? कृपया विस्तार से बताएं। – Jasper

+0

@ जेरी मुझे लगता है कि 'राक्षस' एक बहुलक प्रकार है। उस स्थिति में, पॉलीमोर्फिज्म को सक्षम करने के लिए कुछ प्रकार के पॉइंटर को 'वेक्टर' के तत्व प्रकार के रूप में उपयोग किया जाना चाहिए। – fredoverflow

+0

@FredOverflow: जबकि यह निश्चित रूप से संभव है कि वह एक पॉलिमॉर्फिक पदानुक्रम से निपट सकता है, 1) उसने वास्तव में यह नहीं दिखाया है, और 2) एक वेक्टर अभी भी ठीक होगा यदि यह है। –

0

आप प्रत्येक सूचक को व्यक्तिगत रूप से हटाते हैं, और फिर आप संपूर्ण सरणी को हटा देते हैं। सुनिश्चित करें कि आपने सरणी में संग्रहीत कक्षाओं के लिए एक उचित विनाशक परिभाषित किया है, अन्यथा आप यह सुनिश्चित नहीं कर सकते कि ऑब्जेक्ट्स को ठीक से साफ किया गया हो। सुनिश्चित करें कि आपके सभी विनाशक आभासी हैं ताकि विरासत के साथ उपयोग किए जाने पर वे ठीक तरह से व्यवहार कर सकें।

+0

मुझे लगता है कि दोनों करना अजीब होगा, क्योंकि सरणी स्थिर लंबाई की है, इसलिए आपको इसे हटाने की आवश्यकता नहीं है। इसके अलावा, मैंने विनाशक आभासी घोषित किया, ताकि टिप्पणी बहुत बेकार थी। – Jasper

5

delete[] monsters निश्चित रूप से गलत है। मेरे ढेर डिबगर निम्नलिखित उत्पादन पता चलता है:

allocated non-array memory at 0x3e38f0 (20 bytes) 
allocated non-array memory at 0x3e3920 (20 bytes) 
allocated non-array memory at 0x3e3950 (20 bytes) 
allocated non-array memory at 0x3e3980 (20 bytes) 
allocated non-array memory at 0x3e39b0 (20 bytes) 
allocated non-array memory at 0x3e39e0 (20 bytes) 
releasing  array memory at 0x22ff38 

आप देख सकते हैं, आप हटाना (गैर सरणी बनाम सरणी) का गलत फार्म के साथ रिलीज करने के लिए कोशिश कर रहे हैं, और सूचक है 0x22ff38 कभी नहीं एक से लौटा दिया गया नए को बुलाओवैसे भी

[allocations omitted for brevity] 
releasing non-array memory at 0x3e38f0 
releasing non-array memory at 0x3e3920 
releasing non-array memory at 0x3e3950 
releasing non-array memory at 0x3e3980 
releasing non-array memory at 0x3e39b0 
releasing non-array memory at 0x3e39e0 

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

#include <array> 
#include <memory> 

class Foo 
{ 
    std::array<std::shared_ptr<Monster>, 6> monsters; 

    Foo() 
    { 
     for (int i = 0; i < 6; ++i) 
     { 
      monsters[i].reset(new Monster()); 
     } 
    } 

    virtual ~Foo() 
    { 
     // nothing to do manually 
    } 
}; 
0

यह Sens होगा अगर अपने कोड इस तरह था:

#include <iostream> 

using namespace std; 

class Monster 
{ 
public: 
     Monster() { cout << "Monster!" << endl; } 
     virtual ~Monster() { cout << "Monster Died" << endl; } 
}; 

int main(int argc, const char* argv[]) 
{ 
     Monster *mon = new Monster[6]; 

     delete [] mon; 

     return 0; 
} 
10

आसान बनाने के लिए answare के निम्नलिखित कोड पर नजर डालते हैं:

#include "stdafx.h" 
#include <iostream> 
using namespace std; 

class A 
{ 
private: 
    int m_id; 
    static int count; 
public: 
    A() {count++; m_id = count;} 
    A(int id) { m_id = id; } 
    ~A() {cout<< "Destructor A " <<m_id<<endl; } 
}; 

int A::count = 0; 

void f1() 
{ 
    A* arr = new A[10]; 
    //delete operate only one constructor, and crash! 
    delete arr; 
    //delete[] arr; 
} 

int main() 
{ 
    f1(); 
    system("PAUSE"); 
    return 0; 
} 

उत्पादन होता है: नाशक एक 1 और फिर यह क्रैश हो रहा है (अभिव्यक्ति: _BLOCK_TYPE_IS_VALID (phead-nBlockUse))।

हमें उपयोग करने की आवश्यकता है: हटाएं [] arr; क्योंकि यह पूरी सरणी को हटा देता है और सिर्फ एक सेल नहीं!

हटाएं [] arr का उपयोग करने का प्रयास करें; उत्पादन होता है: नाशक एक 10 नाशक एक 9 नाशक एक 8 नाशक एक 7 नाशक एक 6 नाशक एक 5 नाशक एक 4 नाशक एक 3 नाशक एक 2 नाशक एक 1

ही सिद्धांत पॉइंटर्स की एक सरणी के लिए है:

void f2() 
{ 
    A** arr = new A*[10]; 
    for(int i = 0; i < 10; i++) 
    { 
     arr[i] = new A(i); 
    } 
    for(int i = 0; i < 10; i++) 
    { 
     delete arr[i];//delete the A object allocations. 
    } 

    delete[] arr;//delete the array of pointers 
} 

अगर हम हटाए जाने के बजाय हटाए गए एआर का उपयोग करेंगे [] arr। यह सरणी => पॉइंटर ऑब्जेक्ट्स की स्मृति रिसाव में पूरे पॉइंटर्स को मिटा नहीं देगा!

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