2012-01-14 16 views
7

मैं इस दो वर्गोंसी ++, कॉपी कन्स्ट्रक्टर में std :: vector <Class *> की सही ढंग से प्रतिलिपि कैसे करें?

// This is generic data structure containing some binary data 
class A { 
public: 
    A(); 
    A(const A&); 
    ~A(); 
} 

// Main data container 
class B { 
public: 
    B(); 
    B(const B&); 
    ~B(); 
protected: 
    std::vector<A *> data; 
} 

// Copy constructor for class b 
B::B(const B& orig):data() { 
    for(std::vector<A *>::const_iterator it = orig.data.begin(); 
     it < orig.data.end(); ++it){ 
     data.push_back(new A(*(*it))); 
    } 
} 

मुझे लगता है कि इस वर्ग में यह काम करना होगा उपयोग कर रहा हूँ, लेकिन मैं जिस तरह से कि यह कैसे में कुल पूर्णता तक पहुँचने के लिए करने के लिए लग रहा हूँ।

पहले :data() पर - क्या यह प्रारंभिकरण खाली वेक्टर को सही ढंग से शुरू करने के लिए आवश्यक है (और यह एक अच्छा और साफ कोड लिखने का हिस्सा है)?

कॉपी कन्स्ट्रक्टर में vector::iterator का उपयोग कैसे करें, मुझे मिला एकमात्र तरीका है जिसे मैंने कोड में लिखा है (प्रतिलिपि प्रतिलिपि के लिए अनिवार्य होना चाहिए)।

केवल वेक्टर की प्रतिलिपि सिर्फ सूचक मूल्यों की प्रतिलिपि करेगा, न कि पूरे ऑब्जेक्ट्स?

और अंत में नया डेटा प्रारंभिकरण ... क्या कोई तरीका है कि मैं पूरे लूप को कोड के छोटे टुकड़े से कैसे बदल सकता हूं और/या कोई मानक है कि std :: कंटेनर के लिए प्रतिलिपि बनाने वाले को कैसे लिखना है जिसमें ऑब्जेक्ट पॉइंटर्स हैं?

उप प्रश्न: मैं (, बिजली तय करने के लिए (नहीं) वस्तुओं कॉपी करने के लिए ... हर बार की नकल नहीं) का उपयोग कर vector<A *> और अधिक उपयुक्त और बस vector<A> से विभिन्न कारणों के लिए प्रभावी है यह सोचते हैं रहा हूँ

+0

क्या आपका मतलब "उप प्रश्न: मैं पॉइंटर्स के वेक्टर का उपयोग कर रहा हूं ..." –

+0

प्रारंभकर्ता सूची में 'डेटा' को पूर्वस्थापित करें।' Push_back() 'का उपयोग करना बहुत अप्रभावी है। – lapk

+0

उप उत्तर: मुझे लगता है कि अगर आप पॉइंटर्स का उपयोग नहीं करते हैं, तो आप उन्हें उपयोग नहीं करते हैं। – Lol4t0

उत्तर

9

data() आवश्यक नहीं है क्योंकि यह कन्स्ट्रक्टर में प्रवेश करने से पहले वेक्टर को स्वचालित रूप से किया जाएगा। आपको केवल उन सदस्यों को प्रारंभ करने की आवश्यकता है जो पीओडी प्रकार या प्रकार हैं जिनके पास कोई डिफ़ॉल्ट कन्स्ट्रक्टर नहीं है (या संदर्भ, स्थिरांक, आदि)।

आप वेक्टर को अन्य तत्वों की संख्या के साथ प्रारंभ कर सकते हैं, ताकि वेक्टर को बढ़ने के रूप में स्वयं का आकार बदलना पड़े। यदि आप ऐसा नहीं करते हैं, तो आप एक छोटे से वेक्टर से शुरू कर रहे हैं और इसे आवंटन और आवंटन के माध्यम से गंतव्य आकार तक पहुंचने के लिए तैयार कर रहे हैं।

B::B(const B& orig) : data(orig.data.size()) { 
    for (std::size_t i = 0; i < orig.data.size(); ++i) 
     data[i] = new A(*orig.data[i]); 
} 

सूचना है कि आप push_back किसी भी अधिक का उपयोग नहीं कर रहे हैं, क्योंकि वेक्टर पहले से ही तत्वों कि डिफ़ॉल्ट निर्माण (जिसमें NULL है की orig.data.size() संख्या से भरा है: इस वेक्टर शुरू से ही सही आकार कर देगा पॉइंटर्स का मामला)।

यह कोड को भी ट्रिम करता है क्योंकि आप इसे इटरेटर के बजाय इसे फिर से करने के लिए एक पूर्णांक का उपयोग कर सकते हैं।

तुम सच में iterators का उपयोग करना चाहते हैं, तो आप क्या कर सकते हैं

B::B(const B& orig) : data(orig.data.size()) { 
    // auto is preferable here but I don't know if your compiler supports it 
    vector<A*>::iterator thisit = data.begin(); 
    vector<A*>::const_iterator thatit = orig.data.cbegin(); 

    for (; thatit != orig.data.cend(); ++thisit, ++thatit) 
     *thisit = new A(**thatit); 
} 

इस का लाभ यह है कि यह सिर्फ iterators के प्रकार बदल कर अन्य कंटेनर प्रकार (जैसे list) के साथ काम करेंगे (लेकिन की है अगर आपके पास auto है तो वह दूर जायेगा)।

B::B(const B& orig) : data(orig.data.size()) { 
    try { 
     // auto is preferable here but I don't know if your compiler supports it 
     vector<A*>::iterator thisit = data.begin(); 
     vector<A*>::const_iterator thatit = orig.data.cbegin(); 

     for (; thatit != orig.data.cend(); ++thisit, ++thatit) 
      *thisit = new A(**thatit); 
    } catch (...) { 
     for (vector<A*>::iterator i = data.begin(); i != data.end(); ++i) 
      if (!*i) 
       break; 
      else 
       delete *i; 

     throw; 
    } 
} 

इस तरह आप एक स्मृति रिसाव नहीं होगा अगर new कॉल में से एक एक अपवाद फेंकता है:

आप अपवाद-सुरक्षा जोड़ना चाहते हैं, तो आप एक try/catch ब्लॉक की जरूरत है। बेशक आप try/catch का उपयोग बिना इटरेटर के रास्ते के साथ कर सकते हैं यदि आप इसे इस तरह से करना चाहते हैं।

+1

आपको' मूल 'को अस्वीकार करने की आवश्यकता है। डेटा [i] ' – someguy

+0

@ सोमेगुय व्हाउप्स, आप सही हैं, ठीक है। –

+2

विचार करने के लिए एक और बात यह है कि त्रुटि प्रबंधन है: क्या होता है यदि 'नई' फ़ैय में से एक लूप के बीच में एल? संभवत: कार्यक्रम केवल समाप्त हो जाएगा, लेकिन यदि कॉल स्टैक में मेमोरी त्रुटि को आगे बढ़ाया जाता है तो आपके पास मेमोरी रिसाव होगा। –

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