2012-04-29 11 views
6

में गतिशील सरणी मुझे पता है कि यह एक बहुत पुरानी बहस है जिस पर पूरी दुनिया में कई बार चर्चा की जा चुकी है। लेकिन मुझे वर्तमान में किसी विशेष मामले में स्थैतिक और गतिशील सरणी के बीच किसी अन्य विधि के बजाय किस विधि का उपयोग करना चाहिए, यह तय करने में परेशानी हो रही है। दरअसल, मैंने सी ++ 11 का उपयोग नहीं किया होगा, मैं स्थिर सरणी का उपयोग करता। लेकिन अब मैं उलझन में हूं क्योंकि दोनों के साथ समान लाभ हो सकते हैं।स्टेटिक सरणी वीएस। सी ++ 11

पहले समाधान:

template<size_t N> 
class Foo 
{ 
    private: 
     int array[N]; 

    public: 
     // Some functions 
} 

दूसरा समाधान:

template<size_t N> 
class Foo 
{ 
    private: 
     int* array; 

    public: 
     // Some functions 
} 

मैं चुना है करने के लिए दो अपने स्वयं के लाभ है के बाद से ऐसा नहीं हो सकता:

  • स्टेटिक सरणियों तेजी से कर रहे हैं, और हमें स्मृति प्रबंधन के बारे में परवाह नहीं है।
  • गतिशील सरणी तब तक कुछ भी कम नहीं करती जब तक स्मृति आवंटित नहीं की जाती। उसके बाद, वे स्थैतिक सरणी से उपयोग करने के लिए कम आसान हैं। लेकिन सी ++ 11 के बाद से, हम चलने वाले अर्थशास्त्र से बहुत लाभ प्राप्त कर सकते हैं, जिसे हम स्थिर सरणी के साथ उपयोग नहीं कर सकते हैं।

मुझे नहीं लगता कि एक अच्छा समाधान है, लेकिन मैं कुछ सलाह लेना चाहता हूं या सिर्फ यह जानना चाहता हूं कि आप क्या सोचते हैं।

+2

आपके दो समाधान होना चाहिए: आपका पहला, या एक वेक्टर और कोई आकार_टी टेम्पलेट नहीं होना चाहिए।आपको कच्चे पॉइंटर्स का उपयोग करने से बचना चाहिए जहां किसी भी समस्या के बिना एक एसटीएल कंटेनर का उपयोग किया जा सकता है। – mfontanini

+13

@ फ़ोंटानिनी: यदि आप सी ++ 11 के लिए संशोधित करना चाहते थे, तो दो समाधान 'std :: array ' या 'std :: वेक्टर ' होना चाहिए। –

+1

@ डेविडरोड्रिगुएज़-ड्राईबीस हां सर! – mfontanini

उत्तर

5

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

कभी ऐसी वस्तुओं नहीं हैं जिनमें निर्माण के एक से अधिक चरण हैं। कभी नहीं। यह कुछ बड़े टैटू के माध्यम से स्मृति के लिए प्रतिबद्ध नियम होना चाहिए। बस इसे कभी मत करो।

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

इसके बजाय, यदि आप अपने कार्यक्रम में दो अलग-अलग प्राकृतिक जीवन काल है, दो अलग अलग वस्तुओं का उपयोग करें। लेकिन इसका मतलब है कि आपके कार्यक्रम में आपके दो अलग-अलग राज्य हैं, इसलिए आपके पास एक राज्य मशीन होनी चाहिए, जिसमें एक राज्य में केवल एक वस्तु हो और दोनों के साथ एक अन्य राज्य, एक असीमित घटना से अलग हो। यदि दो बिंदुओं के बीच कोई असीमित घटना नहीं है, यदि वे सभी एक कार्यक्षेत्र में फिट बैठते हैं, तो पृथक्करण कलात्मक है और आपको एकल चरण निर्माण करना चाहिए।

एकमात्र मामला जहां एक अनुवाद समय आकार को गतिशील आवंटन में अनुवाद करना चाहिए, जब आकार ढेर के लिए बहुत बड़ा होता है। इसके बाद यह मेमोरी ऑप्टिमाइज़ेशन हो जाता है, और यह देखने के लिए कि सबसे अच्छा क्या है, इसे स्मृति और प्रोफाइलिंग टूल का उपयोग करके हमेशा मूल्यांकन किया जाना चाहिए। विकल्प 2 कभी भी सर्वश्रेष्ठ नहीं होगा (यह एक नग्न सूचक का उपयोग करता है - इसलिए फिर हम आरएआईआई और किसी भी स्वचालित सफाई और प्रबंधन को खो देते हैं, इनवेरिएंट जोड़ते हैं और कोड को अधिक जटिल और आसानी से दूसरों द्वारा तोड़ने योग्य बनाते हैं)। वेक्टर (जैसा बिटकमास्क द्वारा सुझाया गया है) उपयुक्त पहला विचार होगा, हालांकि आपको समय में ढेर आवंटन लागत पसंद नहीं आती है। अन्य विकल्प आपके एप्लिकेशन की छवि में स्थैतिक स्थान हो सकते हैं। लेकिन फिर, इन्हें केवल तभी माना जाना चाहिए जब आप यह निर्धारित कर लें कि आपके पास स्मृति की बाधा है और वहां से क्या करना चाहिए, वास्तविक मापनीय आवश्यकताओं द्वारा निर्धारित किया जाना चाहिए।

+0

हाँ, आपकी कमी समझ में आता है। मेरे कोड को फिर से पढ़ते समय, मुझे एहसास हुआ कि वास्तव में कभी भी ज़ोंबी ऑब्जेक्ट्स नहीं थी क्योंकि निर्माण में स्मृति आवंटित की गई थी। तो इसके बारे में चिंता मत करो। ठीक है, अंत में चाल संचालन से लाभ केवल लाभ थे (पहले इस्तेमाल होने पर std :: vector द्वारा प्रदान किया गया)। एक वेक्टर का उपयोग करने में केवल एक ही कमी है std :: सरणी की तुलना में कुछ ओवरहेड होगा। लेकिन मुझे नहीं पता कि std :: array ने semantics को स्थानांतरित किया है ... – Morwenn

+0

स्टैक पर, आपको आमतौर पर चाल की आवश्यकता नहीं होती है, आपको रिटर्न वैल्यू ऑप्टिमाइज़ेशन की आवश्यकता होती है, हालांकि कंपाइलर-विशिष्ट, काफी सार्वभौमिक है। अन्य मामलों जहां चाल का उपयोग किया जा सकता है लगभग हमेशा जगह (कोई प्रतिलिपि) नहीं किया जा सकता है, या जब एक प्रति की आवश्यकता होती है, तो वास्तव में इसकी आवश्यकता होती है (एक प्रकार की स्मृति को एक अलग जगह में रखने के लिए), इसलिए चाल काम नहीं करती हैं। – ex0du5

4

न तो उपयोग करें। आप लगभग किसी भी मामले में std::vector का उपयोग बंद कर रहे हैं। अन्य मामलों में, यह इस कारण पर निर्भर करता है कि std::vector अपर्याप्त क्यों होगा और इसलिए आम तौर पर इसका उत्तर नहीं दिया जा सकता है!

+0

मुझे पहले से ही अंगूठे के इस नियम के बारे में पता है। मैं व्यावसायिक काम के लिए होगा, मैं इसका इस्तेमाल करूंगा। हालांकि, मैं प्रयोग करने और अनुभव से अनुभव कमाने के लिए पसंद है। इसके अलावा, मुझे वर्तमान मामले में यादृच्छिक पहुंच की तुलना में वास्तव में कुछ और चाहिए नहीं। यही कारण है कि मैंने इस पर अपना हाथ लगाने की कोशिश की। और, हाँ, जैसा कि std :: वेक्टर कार्यान्वयन पर निर्भर करता है, अगर मैं इस वर्ग के कई उदाहरणों का उपयोग करता हूं तो सरणी के आकार के बाद वास्तव में बदला जाना नहीं है, तो एक बड़ा ओवरहेड हो सकता है। – Morwenn

4

मुझे वर्तमान में यह तय करने में कोई समस्या है कि मुझे किसी विशेष मामले में किसी और से अधिक का उपयोग करना चाहिए।

आपको दिए गए संदर्भ के लिए इष्टतम समाधान निर्धारित करने के लिए अपने विकल्पों को केस-दर-मामले पर विचार करना होगा - यानी, एक सामान्यीकरण नहीं किया जा सकता है। यदि प्रत्येक कंटेनर के लिए एक कंटेनर आदर्श था, तो दूसरा अप्रचलित होगा।

जैसा कि पहले से ही उल्लेख किया गया है, अपना खुद लिखने से पहले std कार्यान्वयन का उपयोग करने पर विचार करें।

अधिक विवरण:

निश्चित लंबाई

  • ढेर आप का उपभोग का कितना से सावधान रहें।
  • यदि आप इसे गतिशील आकार के कंटेनर के रूप में देखते हैं, तो अधिक मेमोरी का उपभोग कर सकते हैं।
  • फास्ट प्रतियां।

चर लंबाई

  • पुनः आबंटन और आकार बदलने महंगा हो सकता है।
  • आवश्यकतानुसार अधिक स्मृति का उपभोग कर सकते हैं।
  • फास्ट चालें।

बेहतर विकल्प भी जरूरी है कि आप निर्माण की जटिलता को समझने, कॉपी, तत्व प्रकार की निर्दिष्ट करते हैं, आदि।

और यदि आप std कार्यान्वयन का उपयोग करते हैं, तो याद रखें कि कार्यान्वयन भिन्न हो सकते हैं। एक सामान्य इंटरफ़ेस के पीछे विस्तार सार संक्षेप -

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

संक्षेप में, आप प्रकार और उपयोग के बारे में एक बहुत कुछ पता है, और एक विशिष्ट परिदृश्य के लिए इष्टतम कंटेनर प्रकार निर्धारित करने के अपने कार्यक्रम के कई पहलुओं को मापने के लिए की जरूरत है।

+1

वर्तमान स्थिति में, चूंकि मुझे एन <4 के लिए टेम्पलेट विशेषज्ञता की आवश्यकता है, मैंने सोचा था कि जब मैं बड़ा होता हूं तो मैं उन लोगों और गतिशील लोगों के लिए स्थैतिक सरणी का उपयोग कर सकता हूं। स्मृति को एक बार आवंटित किया जा रहा है और सरणी का आकार कभी नहीं बदला गया है, यह एक बड़ा ओवरहेड नहीं है। चूंकि मुझे आपके उत्तरों के अंतिम भाग में आपके विचार पसंद हैं। धन्यवाद! – Morwenn

+0

@ मॉर्वेन आपका स्वागत है :) – justin

+1

कॉपी समय कैसे भिन्न होते हैं? – ex0du5