2009-09-07 14 views
5

मैं निम्नलिखित छोटे से कार्यक्रम बना दिया है: (मूल रूप से एक वर्ग अगर यह, बनाया जाता है नकल या नष्ट कर दिया और एक मुख्य बात का कुछ करता है कि COUTS कि)एसटीडी C++ कंटेनर तत्व विनाश और सम्मिलन व्यवहार

class Foo 
{ 
public: 
Foo(string name): _name(name) 
{ 
    cout << "Instance " << _name << " of Foo created!" << std::endl; 
}; 
Foo(const Foo& other): _name(other._name) 
{ 
    cout << "Instance " << _name << " of Foo copied!" << std::endl; 
}; 

~Foo() 
{ 
    cout << "Instance " << _name << " of Foo destroyed!" << std::endl; 
} 
string _name; 
}; 



int main(int argc, char**argv) 
{ 
Foo albert("Albert"); 
Foo bert("Bert"); 
{ 
    vector<Foo> v1, v2; 
    system("PAUSE"); 

    v1.push_back(albert); 
    system("PAUSE"); 

    v2.push_back(bert); 
    system("PAUSE"); 

    v1 = v2; 
    system("PAUSE"); 
} 
    system("PAUSE"); 
} 

आउटपुट इस तरह दिखता है:

Instance Albert of class Foo created! 
Instance Bert of class Foo created! 
Press any key... 
Instance Albert of class Foo copied!  
Instance Albert of class Foo copied!  // why another copy? 
Instance Albert of class Foo destroyed! // and destruction? 
Press any key... 
Instance Bert of class Foo copied! 
Instance Bert of class Foo copied! 
Instance Bert of class Foo destroyed! 
Press any key...      // v1=v2 why did the albert instance not get destroyed? 
Press any key...      
Instance Bert of class A destroyed! 
Instance Bert of class A destroyed! 
Press any key...      // there's still an albert living in the void 

यह मुझे बहुत अजीब तरह से मारता है। यदि मैं दो बार प्रतिलिपि बना देता हूं तो मैं किसी संदर्भ के रूप में कुछ गुजरना क्यों परेशान करता हूं? v1.operator = (अन्य) तत्वों को नष्ट क्यों नहीं करता है? यह shared_ptr के व्यवहार के साथ अच्छी तरह से फिट होगा। क्या कोई मुझे बता सकता है क्यों?

अलावा मैं इस एक अंतहीन लूप में डाल दिया और mem उपयोग की जाँच की, यह कम से कम एक सदस्य रिसाव का उत्पादन करने के प्रतीत नहीं होता।

अतिरिक्त ठीक है, mem कोई समस्या नहीं है क्योंकि यह कॉपी ctor के बजाय ऑपरेटर = का उपयोग करता है, ठीक है धन्यवाद। जब मैं

v1.reserve(10); 
v2.reserve(10); 

जोड़ने प्रतियों की तार्किक संख्या जगह लेता है। इसके बिना यह प्रत्येक एकल push_back के लिए पूरे वेक्टर को पुन: आवंटित करता है और प्रतिलिपि बनाता है, (जिसे मैं छोटे वैक्टरों के लिए भी काफी मंद करता हूं)। इस को देखते हुए मैं और अधिक .reserve उपयोग करने पर विचार और मेरे काम ऑपरेटरों का अनुकूलन नरक की तरह होगा :)

अलावा: सारांश

  1. ये सभी मुद्दे कुलपति ++ 2005 के लिए विशिष्ट लगते हैं।
  2. यदि दो कंटेनरों का आकार मेल खाता है, तो मेरा कार्यान्वयन पुराने लोगों को नष्ट करने और नए लोगों की प्रतिलिपि बनाने के बजाय ध्वनि अभ्यास की बजाय तत्वों पर ऑपरेटर = का उपयोग करता है। यदि आकार भिन्न हैं, सामान्य विनाश और प्रतिलिपि का उपयोग किया जाता है।
  3. 2005 कार्यान्वयन के साथ, किसी को आरक्षित का उपयोग करना होगा! अन्यथा अबाध और std अनुरूप प्रदर्शन नहीं।
  4. ये काले बक्से मेरे विचार से कहीं अधिक काले हैं।
+0

क्या आपने इसे रिलीज बिल्ड के रूप में संकलित करने का प्रयास किया था? – jalf

+0

हां। वही परिणाम – AndreasT

+0

अपने आप को आजमाएं, बस एक खाली परियोजना में पेस्ट कॉपी करें और, iostream, वेक्टर और स्ट्रिंग को शामिल करें, और जाएं। – AndreasT

उत्तर

4

क्यों मैं भी कुछ एक संदर्भ के रूप में अगर यह दो बार वैसे भी कॉपी किया जाता गुजर परेशान करते हो?

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

यह संभव है कि push_back() का आपके कंपाइलर का कार्यान्वयन एक अस्थायी अतिरिक्त प्रति का उपयोग करता है। मेरी मशीन (मैक ओएस एक्स पर जीसीसी) पर, push_back() (आपके प्रोग्राम के आउटपुट के अनुसार) के दौरान कोई अतिरिक्त प्रतियां नहीं हैं।

यह प्रतिलिपि एसटीएल कोड में कहीं होती है, न कि आपकी प्रतिलिपि में (क्योंकि यह संदर्भ का उपयोग करती है)।

v1.operator = (अन्य) तत्वों को नष्ट क्यों नहीं करता है?

Foo::operator= तर्क के रूप में "बर्ट" उदाहरण के साथ "अल्बर्ट" उदाहरण के लिए बुलाया जाएगा। इसलिए, यहां कोई अंतर्निहित विनाश और कॉपी ऑपरेशन नहीं है। आप ऑपरेटर के लिए अपने स्वयं के कार्यान्वयन प्रदान करके इस सत्यापित करने के लिए चाहते हो सकता है:

Foo& operator=(const Foo& other) { 
    cout << "Instance " << other._name << " of Foo assigned to " << _name << "!" << std::endl; 
    return *this; 
} 

यह मेरा मशीन पर निम्न उत्पादन का उत्पादन:

उदाहरण फू के अल्बर्ट बनाया!
फू का इंस्टेंस बर्ट बनाया गया!
फू के इंस्टेंस अल्बर्ट की प्रतिलिपि बनाई गई!
फू का इंस्टेंस बर्ट कॉपी किया गया!
एडबर्ट को सौंपा गया फू का इंस्टेंट बर्ट!
फू का इंस्टेंस बर्ट नष्ट हो गया!
फू का इंस्टेंस अल्बर्ट नष्ट हो गया!
फू का इंस्टेंस बर्ट नष्ट हो गया!
फू का इंस्टेंस अल्बर्ट नष्ट हो गया!

+1

और ध्यान रखें कि प्रतियों का ट्रैक रखने का मतलब है कि आपकी प्रतिलिपि उस बिंदु पर अधिक जटिल हो जाती है जहां अनुकूलक अब इसे खत्म नहीं कर सकता है। तो आप सीटीओआर कॉल की गिनती कर रहे हैं जो केवल इसलिए मौजूद हैं क्योंकि उनकी गणना की जाती है! – MSalters

+0

ब्लैक बॉक्स तर्क मान्य है, तथापि, मैं हमेशा आशा की जाती है इन बेवकूफ ब्लैक बॉक्स :) नहीं थे। खैर अभी तक एक और एम $ निराशा। – AndreasT

+0

@MSalters: यह दिलचस्प है। सी ++ अनिश्चितता सिद्धांत। – stribika

3

एक ऑटो जेनरेट = ऑपरेटर है। जब आप v1 = v2 करते हैं तो ऑपरेटर का उपयोग किया जाता है। उस बिंदु पर "अल्बर्ट" उदाहरणों में से एक "बर्ट" बन जाता है। फू को यह समारोह जोड़ने का प्रयास करें:

Foo& operator = (const Foo& rval) { 
    cout << _name << " = " << rval._name << endl; 
    _name = rval._name; 
    return *this; 
} 

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

+0

अच्छी तरह से और अधिशेष प्रतियों और मेम रिसाव (जो वास्तव में नहीं हो रहा है, ऊपर देखें) – AndreasT

+1

यदि आप यह फ़ंक्शन (या एक स्थिर काउंटर) जोड़ते हैं तो आप देख सकते हैं कि कोई रिसाव नहीं है। अतिरिक्त प्रतियों के लिए कोई गारंटी नहीं है कि एक एसटीएल कंटेनर केवल एक बार चीजों की प्रतिलिपि बनाएगा। यह आपके एसटीएल कार्यान्वयन के आधार पर मूल्य या कुछ अन्य चीज़ों से गुजर सकता है। – stribika

1

जीसीसी के साथ संकलित होने पर "डबल-कॉपीिंग" नहीं होती है। यह वीसी ++ में std :: वेक्टर लागू करने के तरीके के लिए विशिष्ट होना चाहिए।

+0

यह – AndreasT

1

विजुअल स्टूडियो 2008 मेरा पीछा उत्पादन देता है:

Instance Albert of Foo created! 
Instance Bert of Foo created! 
Press any key to continue . . . 
Instance Albert of Foo copied! 
Press any key to continue . . . 
Instance Bert of Foo copied! 
Press any key to continue . . . 
Press any key to continue . . . << here auto-generated operator= doing its job 
Instance Bert of Foo destroyed! 
Instance Bert of Foo destroyed! << this is Albert was originally 
Press any key to continue . . .

है कि std::vector कार्यान्वयन VS2005 में बहुत प्रभावी नहीं है लगता है।

+1

यही सबसे निश्चित रूप से सच VS2005 के लिए विशिष्ट लगता है! – AndreasT

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