2010-08-18 15 views
10

"बड़े 3" के साथ एक सरल वर्ग ले लो (निर्माता, कॉपी निर्माता, नाशक):वाहक: से निपटने के प्रति निर्माता और नाशक (C++)

#include <vector> 
using namespace std; //actually goes in the C file that links to this header file 
... 
class planets(){ //stores mass and radii data for planets in a solar system. 
    public: 
     vector <double> mass; 
     vector <double> radius; 

    //constructor 
    planets(int numObj){ 
    for(int i=0; i<numObj; i++){ 
     mass.push_back(8.0); //some default values. 
     radius.push_back(2.0); 
    } 
    } 
    //copy constructor 
    planets(const planets &p){ 
     vector <double> mass(p.mass); //copy vectors into new class. 
     vector <double> radius(p.radius); 
    } 
    //destructor 
    ~planets(){ 
    delete mass; //ERROR: (...) argument given to ‘delete’, expected pointer 
    ~radius(); //also causes error: no match for call to(...) 
    } 
} 

मैं ग्रहों का एक वेक्टर बनाने पर योजना, इस प्रकार "बड़ा 3" के लिए की जरूरत:

vector <planets> stars; 
stars.push_back(planets(5)); //5 hypothetical planets of alpha centauri 
stars.push_back(planets(8)); //our solar system. Used to be nine. 
///etc. 

मैं कैसे द्रव्यमान और त्रिज्या वैक्टर ठीक से नष्ट कर सकता हूं, मेमोरी लीक (मैं भी करना है) से बचने के लिए?

+4

बीटीडब्ल्यू, आपकी प्रतिलिपि निर्माता (जो बिल्कुल जरूरी नहीं है) ऐसा नहीं कर रहा है जो आपको लगता है कि यह कर रहा है। – jamesdlin

+4

नाइट: बड़े तीन में कॉपी असाइनमेंट ऑपरेटर ('ऑपरेटर =') वेनिला सीटीआर नहीं है। – dirkgently

+2

@dirkgently: यह एक नाइट नहीं है, यह एक मौलिक बिंदु है! –

उत्तर

21

नहीं, आपको कुछ भी करने की आवश्यकता नहीं है क्योंकि आप किसी भी संसाधन का प्रबंधन नहीं कर रहे हैं। जब आप संसाधन प्रबंधित कर रहे हों तो आप केवल बिग थ्री लिखेंगे, लेकिन vector ऐसा कर रहा है। यह बिग थ्री के साथ ठीक से लिखा गया है, आप इसका उपयोग करते हैं।

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

एक प्रबंधन वर्ग में लिखे गए बिग थ्री की आवश्यकता है क्योंकि डिफ़ॉल्ट विशेष सदस्य आम तौर पर गलत चीज करते हैं (वे प्रतिलिपि बनाते हैं, असाइन करते हैं, मूल्यों को प्रबंधित करते हैं या मूल्यों को नियंत्रित करते हैं।) लेकिन एक बार जब आप ' पुनः संसाधन लपेटा गया है (जैसे std::vector में), सब कुछ ठीक है। डिफ़ॉल्ट वेक्टर, लेकिन की प्रतिलिपि बनाएंगे कि प्रतिलिपि सही ढंग से लिखी गई है।

वैसे, बिग थ्री संसाधनों (संसाधनों की प्रतिलिपि बनाने और नष्ट करने) के संदर्भ में है, उन्हें नहीं बनाया गया है। तो यह प्रति-कन्स्ट्रक्टर, कॉपी-असाइनमेंट और विनाशक होगा, डिफ़ॉल्ट कन्स्ट्रक्टर नहीं।


आपकी जानकारी के लिए, यहाँ आप इसे कैसे करना होगा है:

class planets 
{ 
public: 
    // ... 

    //copy constructor 
    planets(const planets &p) : // use an initialization list to initialize 
    mass(p.mass), // copy-construct mass with p.mass 
    radius(p.radius) // copy-construct radius with p.radius 
    { 
     // what you had before just made a local variable, copy-constructed 
     // it with p.xxx, then got released (nothing happened to your members) 
    } 

    //destructor 
    ~planets() 
    { 
     // nothing to do, really, since vector destructs everything 
     // right for you, but you yes, you would delete any resources 
     // you managed here 
    } 
}; 

लेकिन कॉपी-असाइनमेंट ऑपरेटर मत भूलना। मैं copy-and-swap idiom की अनुशंसा करता हूं, और इसे आपके लिए व्यायाम के रूप में छोड़ देता हूं।

(याद रखें कि आप वास्तव में नहीं है इन की जरूरत है, हालांकि।)

4

आपको अपनी कक्षा के लिए किसी भी विनाशक को लागू करने की आवश्यकता नहीं है। वैक्टर स्वचालित रूप से नष्ट हो जाएगा। यह Resource Acquisition Is Initialization पैटर्न से संबंधित है।

1

नहीं - आपको यह नहीं करना है। सदस्य चर के विनाशक स्वचालित रूप से युक्त ऑब्जेक्ट के विनाशक के बाद बुलाए जाते हैं।

-1
~planets(){ 
    mass.clear(); 
    radius.clear(); 
    } 

ऊपर अपने सदस्य वेक्टर वस्तुओं किसी भी संकेत दिए गए की जरूरत नहीं है के रूप में पर्याप्त होना चाहिए।

+0

यहां तक ​​कि आवश्यक नहीं है। 'वेक्टर' वैसे भी स्मृति को अपने विनाशक में छोड़ने जा रहा है। – Naveen

+0

मुझे पता है कि। मैं ओपोस्टर को विनाशक में चीजों को करने का सही तरीका दिखाने की कोशिश कर रहा था। द्रव्यमान हटाएं और ~ त्रिज्या सही नहीं हैं। – Chubsdad

+1

वोट क्यों नीचे? – Chubsdad

0

आपकी विशेष स्थिति में आपको यह नहीं करना है! आप वेक्टर में पॉइंटर्स संग्रहीत नहीं कर रहे हैं। आप अपने ग्रह वर्ग में वैक्टरों को पॉइंटर्स संग्रहीत नहीं कर रहे हैं (यानी आपने गतिशील रूप से वेक्टर <> ऑब्जेक्ट आवंटित नहीं किया है, इसलिए इसे हटाने का प्रयास क्यों करें)।

0

जैसा कि आपने new ed mass नहीं किया था, आपको इसे हटाने की आवश्यकता नहीं है।

इसके अलावा, mass और radius का विनाशकर्ता स्वचालित रूप से बुलाया जाएगा, तो आप उन्हें कॉल करने के लिए की जरूरत नहीं है पर स्पष्ट रूप

4

'तीन बड़ी' आप क्या कहते हैं वे कर रहे हैं नहीं कर रहे हैं। वे हैं: कॉपी कन्स्ट्रक्टर, कॉपी असाइनमेंट ऑपरेटर और विनाशक।

vector उदाहरण पहले से ही कॉम्पैक्टिव और असाइन करने योग्य हैं, आपको vector<double> के दो सदस्यों के साथ कुछ भी विशेष करने की ज़रूरत नहीं है, आपको बड़े तीनों के कस्टम कार्यान्वयन की आवश्यकता नहीं है।

आपकी प्रतिलिपि निर्माता गलत है, यह स्रोत वर्गों को नई कक्षा में कॉपी नहीं करता है, यह सिर्फ उन लोगों से फ़ंक्शन स्थानीय बनाता है जिन्हें हटा दिया जाता है। यह mass और radius नामक स्थानीय चर बनाता है जो समान नाम वाले सदस्य चर को मुखौटा करते हैं।

planets(const planets &p){ 
    vector <double> mass(p.mass); //copy vectors into new class. 
    vector <double> radius(p.radius); 
} 

अधिक सही (लेकिन अनावश्यक) होगा:

planets(const planets &p) 
    : mass(p.mass) //copy vectors into new class. 
    , radius(p.radius) 
{ 
} 

इसी तरह अपने नाशक शरीर खाली होना चाहिए। आप केवल delete पॉइंटर्स जिन्हें new के साथ आवंटित किया गया है। जैसा कि आपके पास सीधे सदस्य चर है, कोई विशेष कार्रवाई की आवश्यकता नहीं है।

+0

लेकिन इससे भी अधिक सही संकलक उत्पन्न डिफ़ॉल्ट संस्करण का उपयोग नहीं किया जाएगा। –

2

आपका वर्ग भी सरल किया जा सकता:

class planets() 
{ //stores mass and radii data for planets in a solar system. 
    public: 
    std::vector<double> mass; 
    std::vector<double> radius; 

    //constructor 
    planets(int numObj) 
    { 
    for(int i=0; i<numObj; i++) 
    { 
     mass.push_back(8.0); //some default values. 
     radius.push_back(2.0); 
    } 
    } 
} 

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

  • कॉपी ही
  • से अधिक आवंटित किया
  • नष्ट itselft

संकलक उत्पन्न प्रतिलिपि निर्माता असाइनमेंट ऑपरेटर और नाशक स्वचालित रूप से किसी पर इन आपरेशनों कॉल करेगा: प्रत्येक वर्ग कैसे पता करने के लिए माना जाता है सदस्य चर (द्रव्यमान और त्रिज्या) ताकि आपको भी आवश्यकता न हो। तो आपके मामले में std :: वेक्टर जानता है कि सभी तीन परिचालनों को सही तरीके से कैसे करें और इसलिए आपको कोई अतिरिक्त कोड जोड़ने की आवश्यकता नहीं है।

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