2011-01-15 18 views
13

कॉपी कन्स्ट्रक्टर और सी ++ में कॉपी असाइनमेंट ऑपरेटरों के बारे में पढ़ने के बाद, मैंने एक साधारण उदाहरण बनाने की कोशिश की। हालांकि नीचे स्निपेट स्पष्ट रूप से काम करता है, मुझे यकीन नहीं है कि मैं कॉपी कन्स्ट्रक्टर को कार्यान्वित कर रहा हूं और असाइनमेंट ऑपरेटर को सही तरीके से कॉपी कर रहा हूं। क्या आप कृपया बता सकते हैं कि क्या कोई गलती/सुधार या प्रासंगिक अवधारणाओं को समझने के लिए एक बेहतर उदाहरण है।सी ++: कॉपी कन्स्ट्रक्टर और कॉपी असाइनमेंट ऑपरेटर को कार्यान्वित करना

class Foobase 
{ 
    int bInt; 

public: 
    Foobase() {} 

    Foobase(int b) { bInt = b;} 

    int GetValue() { return bInt;} 

    int SetValue(const int& val) { bInt = val; } 
}; 


class Foobar 
{ 
    int var;  
    Foobase *base;  

public: 
    Foobar(){} 

    Foobar(int v) 
    { 
     var = v;   
     base = new Foobase(v * -1); 

    } 

    //Copy constructor 
    Foobar(const Foobar& foo) 
    {  
     var = foo.var; 
     base = new Foobase(foo.GetBaseValue()); 
    } 

    //Copy assignemnt operator 
    Foobar& operator= (const Foobar& other) 
    { 
     if (this != &other) // prevent self-assignment 
     { 
      var = other.var; 
      base = new Foobase(other.GetBaseValue()); 

     } 
     return *this; 
    } 

    ~Foobar() 
    { 
     delete base; 
    } 

    void SetValue(int val) 
    { 
     var = val; 
    } 

    void SetBaseValue(const int& val) 
    { 
     base->SetValue(val); 
    } 

    int GetBaseValue() const 
    { 
     return(base->GetValue()); 
    } 

    void Print() 
    { 
     cout<<"Foobar Value: "<<var<<endl; 
     cout<<"Foobase Value: "<<base->GetValue()<<endl; 

    } 

}; 

int main() 
{ 
    Foobar f(10);  
    Foobar g(f); //calls copy constructor 
    Foobar h = f; //calls copy constructor 

    Foobar i; 
    i = f; 

    f.SetBaseValue(12); 
    f.SetValue(2);  

    Foobar j = f = z; //copy constructor for j but assignment operator for f 

    z.SetBaseValue(777); 
    z.SetValue(77); 

    return 1; 
} 

उत्तर

12

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

आपकी डिफ़ॉल्ट निर्माता भी गलत है: यह दोनों base और var अप्रारंभीकृत छोड़ देता है, तो वहाँ कोई रास्ता नहीं जानना चाहता है कि वैध और नाशक में है या तो है, जब आप delete base; कहते हैं, बुरा बातें होती हैं।

कॉपी कन्स्ट्रक्टर और कॉपी असाइनमेंट ऑपरेटर को लागू करने का सबसे आसान तरीका और यह जानना कि आपने the Copy-and-Swap idiom का उपयोग करना सही तरीके से किया है।

+1

+1 अच्छा बिंदु कॉपी और स्वैप मुहावरे एक अपवाद सुरक्षित कार्यान्वयन के लिए आवश्यक है जो ऑब्जेक्ट को एक स्थिर स्थिति में रहने की गारंटी देता है। – jdehaan

+0

क्या विनाशक '~ Foobar() 'द्वारा स्मृति को मुक्त नहीं किया जाएगा? – blitzkriegz

+0

@ महात्मा: '~ Foobar()' नहीं कहा जाएगा; वस्तु कभी नष्ट नहीं होती है, इसे सौंपा जाता है। –

2

केवल Foobar को कस्टम कॉपी कन्स्ट्रक्टर, असाइनमेंट ऑपरेटर और विनाशक की आवश्यकता है। Foobase को एक की आवश्यकता नहीं है क्योंकि संकलक देता है कि डिफ़ॉल्ट व्यवहार पर्याप्त है।

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

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

इसके अलावा, Foobar का डिफ़ॉल्ट कन्स्ट्रक्टर डिफ़ॉल्ट नहीं है-सदस्यों को प्रारंभ करें। यह बुरा है, क्योंकि यह वह नहीं है जो उपयोगकर्ता अपेक्षा करेगा। सदस्य सूचक एक मनमाना पते पर इंगित करता है और int के मनमाना मूल्य होता है। अब यदि आप ऑब्जेक्ट का उपयोग करते हैं तो कन्स्ट्रक्टर बनाया गया है, तो आप अपरिभाषित व्यवहार भूमि के बहुत पास हैं।

class Foobar 
{ 
    int var;  
    std::unique_ptr<FooBase> base; 

... 

कि आरंभ करना चाहिए:

+0

यदि मैं मूल मेमोरी को मुक्त करने के लिए नए आवंटन से पहले 'डिलीट बेस 'करता हूं, तो मुझे' डबल फ्री या भ्रष्टाचार 'त्रुटि मिलती है। मैं मुहावरे में देख लूंगा। मुझे खाली डिफ़ॉल्ट कन्स्ट्रक्टर के साथ समस्या के बारे में अंतिम भाग नहीं मिला। क्या मुझे 'var = SOMEVALUE;' और 'base = NULL' रखना चाहिए, क्योंकि मेरे उदाहरण में, मैं पैरामीटरयुक्त कन्स्ट्रक्टर का उपयोग करता हूं। – blitzkriegz

+0

* नई अभिव्यक्ति * में कोष्ठक की अनुपस्थिति केवल रचनाकारों के बिना प्रकारों के लिए एक अंतर बनाती है, जो यहां के किसी भी प्रकार के नहीं हैं। * कम-से-कम एक उपयोगकर्ता द्वारा परिभाषित कन्स्ट्रक्टर वाले प्रकारों का डिफ़ॉल्ट-प्रारंभिक * डिफ़ॉल्ट कन्स्ट्रक्टर को कॉल उत्पन्न करता है। –

+0

पेडेंटिक रूप से, डिफ़ॉल्ट कन्स्ट्रक्टर डीईईएस * डिफ़ॉल्ट-प्रारंभिक * सदस्यों (* * ctor-initializer * नहीं होने के कारण, किसी भी * mem-startizer-id * में उनका उल्लेख नहीं किया गया है, और मानक निर्दिष्ट करता है कि वे * डिफ़ॉल्ट-प्रारंभिक हैं * इस मामले में)। लेकिन 'int' का डिफ़ॉल्ट प्रारंभिकरण राज्य को अनिर्दिष्ट छोड़ देता है। –

0

मैं तुम्हारे लिए एक बहुत ही सरल पैच है।

लब्बोलुआब यह है:

  1. अपने कोड में delete फोन न करें (विशेषज्ञों को देखने के बिंदु 2)
  2. अपने कोड में delete फोन न करें (आप बेहतर जानते हैं ...)
+0

कंपाइलर के साथ प्रदान की गई सी ++ लाइब्रेरी की उम्र के आधार पर, यह 'std :: tr1 :: unique_ptr' हो सकता है ... –

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