2010-01-17 12 views
13

के निजी सदस्य के रूप में ऐरे मैं एक कक्षा बनाने की कोशिश कर रहा हूं जिसमें एक निजी सदस्य है जो एक सरणी है। मैं सरणी के आकार को नहीं जानता और जब तक कि निर्माता को कन्स्ट्रक्टर में पास नहीं किया जाता है। क्लास कन्स्ट्रक्टर को परिभाषित करने के साथ-साथ .h फ़ाइल में परिभाषा को सरणी के इस चर आकार के लिए अनुमति देने का सबसे अच्छा तरीका क्या है?कक्षा

उत्तर

10

आप एक 'असली' सी-शैली सरणी चाहते हैं, तो आप अपने वर्ग के लिए एक सूचक निजी सदस्य जोड़ने के लिए, और गतिशील रूप से (नई साथ) निर्माता में इसके लिए स्मृति को आबंटित करने की है। जाहिर है आप इसे विनाशक में मुक्त करना नहीं भूलना चाहिए।

class YourClass 
{ 
    private: 
    int * array; 
    size_t size; 

    // Private copy constructor operator to block copying of the object, see later 
    // C++03: 
    YourClass(const YourClass &); // no definition 
    // C++11: 
    YourClass(const YourClass&) = delete; 

    public: 
    YourClass(size_t Size) : array(new int[Size]), size(Size) 
    { 
     // do extra init stuff here 
    }; 

    ~YourClass() 
    { 
     delete [] array; 
    } 
}; 

इस काम को आसान बनाने के लिए, आप (उदाहरण के लिए, एक boost::scoped_array सी ++ 03, या सादे std::unique_ptr सी ++ 11 में में) एक स्मार्ट सूचक का उपयोग करने पर विचार कर सकते हैं, तो आप प्रारंभकर्ता का उपयोग कर प्रारंभ हो सकता है कि कन्स्ट्रक्टर या बस कन्स्ट्रक्टर में पहले सूची।

class YourClass 
{ 
    private: 
    boost::scoped_array<int> array; // or in C++11 std::unique_ptr<int[]> array; 
    size_t size; 
    public: 
    YourClass(size_t Size) : array(new int[Size]), size(Size) 
    { 
     // do extra init stuff here 
    } 

    // No need for a destructor, the scoped_array does the magic 
}; 

इन दोनों समाधान noncopyable वस्तुओं का उत्पादन (अगर वे copyable होने के लिए और उनके प्रति अर्थ था आप निर्दिष्ट नहीं किया है); यदि कक्षा की प्रतिलिपि बनाने की आवश्यकता नहीं है (जो कि अधिकतर बार होता है), तो ये दोनों ठीक हैं, और संकलक एक त्रुटि उत्पन्न करेगा यदि आप एक वर्ग को दूसरी श्रेणी में कॉपी/असाइन करने का प्रयास करते हैं, तो पहले मामले में डिफ़ॉल्ट प्रतिलिपि दूसरे मामले में कन्स्ट्रक्टर को एक निजी (या सी ++ 11 में हटाया गया सादा) के साथ ओवरलोड किया गया है क्योंकि boost::scoped_array और std::unique_ptr गैर-लोकप्रिय हैं।

यदि, इसके बजाय, आप कॉपी करने योग्य ऑब्जेक्ट्स चाहते हैं, तो आपको यह तय करना होगा कि क्या आप एक प्रतिलिपि बनाना चाहते हैं जो सरणी साझा करता है (इसलिए, केवल एक पॉइंटर प्रतिलिपि) या यदि आप एक नया, अलग सरणी बनाना चाहते हैं दूसरी वस्तु।

पहले मामले में, आवंटित स्मृति को मुक्त करने से पहले आपको बहुत सावधान रहना चाहिए, क्योंकि अन्य वस्तुएं इसका उपयोग कर सकती हैं; एक संदर्भ-काउंटर सबसे आम समाधान है। आप boost::shared_array (या std::shared_ptr सी ++ 11 में) में इसकी सहायता कर सकते हैं, जो आपके लिए स्वचालित रूप से सभी ट्रैकिंग कार्य करता है।

यदि आप इसके बजाय "गहरी प्रतिलिपि" करना चाहते हैं, तो आपको नई मेमोरी आवंटित करनी होगी और स्रोत सरणी की सभी ऑब्जेक्ट को लक्ष्य सरणी में कॉपी करना होगा। यह सही ढंग से करने के लिए पूरी तरह से तुच्छ नहीं है, और आमतौर पर "copy and swap idiom" के माध्यम से पूरा किया जाता है।

फिर भी, सबसे आसान समाधान std::vector को एक निजी सदस्य के रूप में उपयोग करना है: यह आपके द्वारा बनाई गई सभी आवंटन/विध्वंस सामग्री को स्वयं ही व्यवस्थित/नष्ट कर देगा, जब आपकी कक्षा का उद्देश्य बनाया/नष्ट हो जाए। इसके अलावा, यह बॉक्स के बाहर अर्थपूर्ण गहरी प्रतिलिपि लागू करता है। यदि आपको अपने कॉलर्स को केवल पढ़ने के लिए वेक्टर तक पहुंचने की आवश्यकता है, तो आप या constvector ऑब्जेक्ट के संदर्भ में एक गेटर लिख सकते हैं।

+1

सरणी के लिए, आप ' scoped_array', 'scoped_ptr' नहीं। –

+0

सही, धन्यवाद। मुझे हमेशा हटाएं [] सही मिलता है, लेकिन कभी-कभी मैं स्मार्ट पॉइंटर्स के सरणी संस्करणों के बारे में भूल जाता हूं। –

+0

एकमात्र झुकाव यह है कि यदि आपका क्लास कॉपी करने योग्य है, क्योंकि scoped_ * बूस्ट में noncopyable है। यह वैसे भी सवाल में निर्दिष्ट नहीं है, इसलिए किसी भी तरह +1 करें। – Skurmedel

2

एक std :: वेक्टर का उपयोग करना सबसे अच्छा विकल्प है। यदि आपको कभी किसी ऐसे फ़ंक्शन पर पास करने की आवश्यकता है जो किसी सूचक को एक सरणी (जैसे जीएसएल अक्सर करता है) की अपेक्षा करता है, तो आप अभी भी &vec[0] पास कर सकते हैं ...