std :: वेक्टर बनाम std :: सरणी में C ++


283

C ++ में a std::vectorऔर a के बीच क्या अंतर हैं std::array? एक दूसरे पर कब पसंद किया जाना चाहिए? प्रत्येक का भला - बुरा क्या है? मेरी सभी पाठ्यपुस्तक सूची है कि वे समान कैसे हैं।


1
मैं std::vectorबनाम की तुलना के लिए देख रहा हूँ std::arrayऔर कैसे शब्द अलग हैं।
जूड

Zud, std::arrayC ++ सरणी के समान नहीं है। std::arrayC ++ सरणियों के चारों ओर एक बहुत पतला आवरण है, जो कक्षा के उपयोगकर्ता से सूचक को छिपाने का प्राथमिक उद्देश्य है। मैं अपना जवाब अपडेट करूंगा।
क्लोज कॉउबॉय

मैंने आपके स्पष्टीकरण को दर्शाने के लिए प्रश्न शीर्षक और पाठ को अद्यतन किया।
मट्टियो इटालिया

जवाबों:


318

std::vectorएक टेम्प्लेट क्लास है जो एक डायनेमिक ऐरे 1 को एनकैप्सुलेट करता है, जो कि हीप में संचित होता है, जो तत्वों के जुड़ने या हटने पर अपने आप बढ़ता और सिकुड़ता है। यह सभी हुक ( begin()और end(), पुनरावृत्तियों, आदि) प्रदान करता है जो इसे बाकी एसटीएल के साथ ठीक काम करते हैं। इसमें कई उपयोगी विधियां भी हैं जो आपको ऑपरेशन करने देती हैं जो एक सामान्य सरणी पर बोझिल होगा, जैसे कि वेक्टर के बीच में तत्वों को सम्मिलित करना (यह पर्दे के पीछे निम्नलिखित तत्वों को स्थानांतरित करने के सभी काम को संभालता है)।

चूंकि यह ढेर पर आवंटित स्मृति में तत्वों को संग्रहीत करता है, इसमें स्थिर सरणियों के संबंध में कुछ ओवरहेड है।

std::arrayएक टेम्प्लेट क्लास है जो स्टैटिक-साइज़ ऐरे को एनकैप्सुलेट करता है, जो ऑब्जेक्ट के अंदर ही स्टोर होता है, जिसका मतलब है कि, यदि आप स्टैक पर क्लास को इंस्टेंट करते हैं, तो ऐरे खुद स्टैक पर होगा। इसका आकार संकलन समय पर जाना जाता है (यह एक टेम्पलेट पैरामीटर के रूप में पारित किया जाता है), और यह बढ़ या सिकुड़ नहीं सकता है।

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

एक परिचय के लिए std::array, इस लेख पर एक नज़र डालें ; std::vectorइस पर होने वाले कार्यों के त्वरित परिचय के लिए , आप इसके प्रलेखन को देखना चाहते हैं ।


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

6
आपके फुटनोट के बारे में: जबकि यह सच है, मानक यह भी संकेत देता है कि आंतरिक तत्वों पर सूचक अंकगणित काम करता है, जिसका अर्थ है कि यह एक सरणी होना चाहिए: & vec [९] - & vec [३] == ६ सच है।
ल्यूक्रिएल

9
मुझे पूरा यकीन है, कि वेक्टर अपने आप सिकुड़ता नहीं है, लेकिन C ++ 11 के बाद से आप संकोचन_टो_फिट कह सकते हैं।
डीनो

मैं शब्द स्थिर सरणी से पूरी तरह से भ्रमित हूं और मुझे यकीन नहीं है कि सही शब्दावली क्या है। आप एक स्थिर आकार सरणी का मतलब है और एक स्थिर चर सरणी नहीं है (एक स्थिर भंडारण का उपयोग कर)। stackoverflow.com/questions/2672085/… । सही शब्दावली क्या है? स्थिर सरणी एक निश्चित आकार के साथ एक सरणी के लिए एक मैला शब्द है?
Z boson

3
@Zboson: यह निश्चित रूप से सिर्फ आप ही नहीं है, स्थैतिक काफी दुरुपयोग शब्द है; staticC ++ में बहुत कीवर्ड के तीन अलग-अलग असंबंधित अर्थ हैं, और इस शब्द का उपयोग अक्सर सामान के बारे में बात करने के लिए भी किया जाता है जो कि संकलन समय पर तय किया जाता है। मुझे उम्मीद है कि "सांख्यिकीय रूप से आकार" थोड़ा अधिक स्पष्ट है।
मट्टियो इतालिया

3
एक बात पर ध्यान दें: वास्तविक समय की प्रोग्रामिंग के लिए (जहां आपको स्टार्टअप के बाद कोई डायनेमिक आवंटन / डीललैशन नहीं होना चाहिए ) std :: array शायद std से अधिक पसंद की जाएगी :: वेक्टर।
TED

17

std::vector<T>वर्ग का उपयोग करना :

  • ... बिल्ट-इन सरणियों का उपयोग करने के रूप में उपवास है , यह मानते हुए कि आप केवल अंतर्निहित सरणियों में काम कर रहे हैं (आपको मौजूदा तत्वों को पढ़ने और लिखने की अनुमति देता है)।

  • ... नए तत्वों को सम्मिलित किए जाने पर स्वचालित रूप से आकार बदल जाता है।

  • ... आपको शुरुआत में या वेक्टर के बीच में नए तत्वों को सम्मिलित करने की अनुमति देता है , स्वचालित रूप से "शेष" तत्वों को "ऊपर" स्थानांतरित करता है (क्या इसका कोई मतलब है?)। यह आपको तत्वों को कहीं भी हटाने की अनुमति देता है std::vector, साथ ही, शेष तत्वों को स्वचालित रूप से नीचे स्थानांतरित कर रहा है।

  • ... आपको at()विधि के साथ एक रेंज-चेक रीड करने की अनुमति देता है ( []यदि आप चाहते हैं कि आप इस चेक को निष्पादित नहीं करना चाहते हैं तो आप हमेशा इंडेक्सर्स का उपयोग कर सकते हैं )।

कर रहे हैं दो का उपयोग कर के लिए तीन मुख्य चेतावनियां std::vector<T>:

  1. आपके पास अंतर्निहित पॉइंटर तक विश्वसनीय पहुंच नहीं है, जो कि एक मुद्दा हो सकता है यदि आप तृतीय-पक्ष फ़ंक्शन के साथ काम कर रहे हैं जो किसी सरणी के पते की मांग करते हैं।

  2. std::vector<bool>वर्ग मूर्खतापूर्ण है। यह एक संघनित बिटफील्ड के रूप में कार्यान्वित किया जाता है, न कि एक सरणी के रूप में। यदि आप boolएस की एक सरणी चाहते हैं तो इसे टालें !

  3. उपयोग के दौरान, std::vector<T>समान C तत्वों के साथ C ++ सरणी की तुलना में थोड़ा बड़ा होने वाला है। ऐसा इसलिए है क्योंकि उन्हें अन्य जानकारी, जैसे कि उनके वर्तमान आकार, और जब भी std::vector<T>आकार बदलते हैं, तो उन्हें अधिक स्थान आरक्षित रखने की आवश्यकता होती है। यह उन्हें हर बार नए तत्व के आकार बदलने से रोकने के लिए है। इस व्यवहार को एक प्रथा प्रदान करके बदला जा सकता है allocator, लेकिन मुझे ऐसा करने की आवश्यकता कभी महसूस नहीं हुई!


संपादित करें: Zud के प्रश्न के उत्तर को पढ़ने के बाद, मुझे लगा कि मुझे इसे जोड़ना चाहिए:

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


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

4
सी ++ 11 में गैर bool सदिशों के लिए और बाद में, आप कॉल कर सकते हैं data()एक पर std::vector<T>अंतर्निहित सूचक मिलता है। आप केवल तत्व 0 का पता भी ले सकते हैं (C ++ 11 के साथ काम करने की गारंटी, संभवतः पहले के संस्करणों के साथ काम करेंगे)।
मैट

16

@MatteoItalia द्वारा किए गए एक बिंदु पर जोर देने के लिए, दक्षता अंतर वह है जहां डेटा संग्रहीत किया जाता है। हीप मेमोरी (साथ की vectorआवश्यकता) मेमोरी को आवंटित करने के लिए सिस्टम को कॉल की आवश्यकता होती है और यदि आप चक्र गिन रहे हैं तो यह महंगा हो सकता है। स्टैक मेमोरी (संभव के लिए array) समय के संदर्भ में लगभग "शून्य-ओवरहेड" है, क्योंकि स्टैक पॉइंटर को सिर्फ समायोजित करके मेमोरी आवंटित की जाती है और यह केवल एक फ़ंक्शन के प्रवेश पर एक बार किया जाता है। स्टैक भी स्मृति विखंडन से बचा जाता है। सुनिश्चित करने के लिए, std::arrayहमेशा स्टैक पर नहीं होंगे; यह इस बात पर निर्भर करता है कि आप इसे कहाँ आवंटित करते हैं, लेकिन यह अभी भी वेक्टर की तुलना में ढेर से एक कम मेमोरी आवंटन को शामिल करेगा। अगर आपके पास एक है

  • छोटा "सरणी" (100 तत्वों के तहत) - (एक विशिष्ट स्टैक लगभग 8 एमबी है, इसलिए स्टैक पर कुछ केबी से अधिक आवंटित न करें या यदि आपका कोड पुनरावर्ती है तो कम)
  • आकार तय हो जाएगा
  • जीवनकाल फंक्शन स्कोप में है (या माता-पिता वर्ग के समान जीवनकाल के लिए एक सदस्य मूल्य है)
  • आप चक्र गिन रहे हैं,

निश्चित रूप std::arrayसे एक वेक्टर पर एक का उपयोग करें । यदि उन आवश्यकताओं में से कोई भी सत्य नहीं है, तो एक का उपयोग करें std::vector


3
अच्छा उत्तर। "सुनिश्चित होने के लिए, std :: सरणी हमेशा स्टैक पर नहीं होगी; यह इस बात पर निर्भर करता है कि आप इसे कहाँ आवंटित करते हैं" तो मैं कैसे एक std बना सकता हूँ :: सरणी ढेर पर नहीं तत्वों की एक बड़ी संख्या के साथ?
ट्रिलियनियन

4
@ परीक्षण का उपयोग करें new std::arrayया इसे उस वर्ग का सदस्य बनाएं जिसे आप आवंटित करने के लिए 'नए' का उपयोग करते हैं।
निशान लता जनता

तो इसका मतलब यह है कि new std::arrayअभी भी उम्मीद है कि इसका आकार संकलन समय पर होगा और इसका आकार नहीं बदल सकता है, लेकिन फिर भी यह ढेर पर रहता है?
ट्रिलरियन

हाँ। new std::arrayबनाम का उपयोग करने के लिए एक महत्वपूर्ण लाभ नहीं है new std::vector
मार्क लकाटा

12

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

निम्नलिखित घोषणाओं को देखते हुए:

int cConc[3][5];
std::array<std::array<int, 5>, 3> aConc;
int **ptrConc;      // initialized to [3][5] via new and destructed via delete
std::vector<std::vector<int>> vConc;    // initialized to [3][5]

C-style array (cConc) या std :: array (aConc) में पहले तत्व के लिए एक पॉइंटर को प्रत्येक पूर्ववर्ती तत्व में 1 जोड़कर पूरे सरणी के माध्यम से पुनरावृत्त किया जा सकता है। उन्हें कसकर पैक किया जाता है।

वेक्टर ऐरे (vConc) या पॉइंटर ऐरे (ptrConc) में पहले तत्व के लिए एक संकेतक केवल पहले 5 (इस मामले में) तत्वों के माध्यम से पुनरावृत्त हो सकता है, और फिर ओवरहेड के लिए 12 बाइट्स (मेरे सिस्टम पर) हैं अगला वेक्टर

इसका अर्थ यह है कि एक std :: वेक्टर> एरे को एक [3] [1000] के रूप में आरंभीकृत किया गया है, एक [1000] [3] एरे के रूप में आरम्भिक की तुलना में मेमोरी में सरणी बहुत छोटी होगी, और दोनों एक std की तुलना में मेमोरी में बड़ी होंगी: सरणी को दोनों तरह से आवंटित किया गया।

इसका मतलब यह भी है कि आप केवल एक ओवरडायनामिक वेक्टर (या पॉइंटर) एरे को पास नहीं कर सकते हैं, कह सकते हैं, मेमोरी ओवरहेड के लिए अकाउंटिंग के बिना ओपनजीएल, लेकिन आप ओपन करने के लिए एक बहुआयामी एसटी :: सरणी पास कर सकते हैं और इसे काम कर सकते हैं।


-17

एक वेक्टर एक कंटेनर वर्ग है जबकि एक सरणी एक आवंटित स्मृति है।


23
आपका उत्तर std::vector<T>बनाम पता लगता है T[], लेकिन सवाल std::vector<T>बनाम के बारे में है std::array<T>
कीथ पिंसन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.