वेक्टर के बीच पसंद :: आकार () और वेक्टर :: रिजर्व ()


151

मैं अपने vectorसदस्य चर को कुछ स्मृति पूर्व-आवंटित कर रहा हूं । नीचे कोड न्यूनतम हिस्सा है

class A {
  vector<string> t_Names;
public:
  A () : t_Names(1000) {}
};

अब किसी समय, अगर t_Names.size()बराबर है 1000। मैं आकार बढ़ाने का इरादा कर रहा हूं 100। फिर अगर यह पहुंच जाता है 1100, तो फिर से 100और इतने पर बढ़ जाता है ।

मेरा प्रश्न क्या के बीच चयन करने के लिए है, vector::resize()और vector::reserve()। क्या इस तरह के परिदृश्य में कोई बेहतर विकल्प है?

संपादित करें : मेरे पास इसके लिए सटीक अनुमान है t_Names। मुझे लगता है कि यह चारों ओर 700है 800। हालांकि कुछ (शायद ही कभी) स्थितियों में, यह अधिक से अधिक बढ़ सकता है 1000


34
आपको पता चलता है कि ऐसा करने का अर्थ है कि वेक्टर विकास अब निरंतर समय नहीं देता है और आप उपयोग के प्रदर्शन लाभों में से एक को खो देते हैं std::vector
ब्लास्टफर्नस

1
संबंधित, देखें सी ++ मेड ईज़ीयर: डॉ। डॉब्स साइट पर वैक्टर कैसे बढ़ते हैं
jww

जवाबों:


262

दो कार्य बहुत अलग चीजें करते हैं!

resize()विधि (और निर्माता के लिए तर्क गुजर कि के बराबर है) से जोड़ दिया जाएगा या वेक्टर के तत्वों की हटाने की उपयुक्त संख्या यह दिए गए आकार बनाने के लिए (यह उनके मूल्य निर्दिष्ट करने के लिए वैकल्पिक दूसरा तर्क है)। यह प्रभावित करेगा size(), पुनरावृत्ति उन सभी तत्वों पर चला जाएगा, पुश_बैक उनके बाद सम्मिलित करेगा और आप सीधे उपयोग करके उनका उपयोग कर सकते हैं operator[]

reserve()विधि केवल स्मृति आबंटित करता है, लेकिन पत्तियों यह अप्रारंभीकृत। यह केवल प्रभावित करता है capacity(), लेकिन size()अपरिवर्तित रहेगा। वस्तुओं के लिए कोई मूल्य नहीं है, क्योंकि वेक्टर में कुछ भी नहीं जोड़ा गया है। यदि आप तत्वों को सम्मिलित करते हैं, तो कोई वास्तविक स्थिति नहीं होगी, क्योंकि यह पहले से किया गया था, लेकिन यह एकमात्र प्रभाव है।

तो यह निर्भर करता है कि आप क्या चाहते हैं। यदि आप 1000 डिफ़ॉल्ट आइटम की एक सरणी चाहते हैं, तो उपयोग करें resize()। यदि आप एक ऐसी सारणी चाहते हैं, जिसमें आप 1000 वस्तुओं को सम्मिलित करने की अपेक्षा करते हैं और एक-दो आवंटन से बचना चाहते हैं, तो उपयोग करें reserve()

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

EDIT2: विज्ञापन प्रश्न संपादित करें: यदि आपके पास प्रारंभिक अनुमान है, तो reserve()वह अनुमान है। यदि यह पर्याप्त नहीं है, तो वेक्टर को यह करने दें।


मैंने प्रश्न संपादित किया है। मेरे पास इसके लिए कुछ अनुमान है vector
.मिलिंद

3
@ जान: यह आवश्यक संपत्ति को बनाए रखने के लिए आपके लिए कितना कठिन है, इसके अनुसार यह नाजुक है या नहीं। कुछ ऐसा x.reserve(x.size() + newdata); vector<int>::iterator special_element = get_special_element(x); for (int i = 0; i < newdata; ++i) { if some_function(i, special_element) x.push_back(i); }ही बहुत मजबूत है जहां तक ​​अंतरिक्ष को जलाने का संबंध है। मुझे नहीं पता कि वास्तव में कितने तत्व जोड़े जाएंगे, लेकिन मेरे पास एक ऊपरी सीमा है। बेशक जब संदेह है, तो वैक्टर के साथ आप केवल पुनरावृत्तियों के बजाय अनुक्रमित का उपयोग कर सकते हैं, अंतर आमतौर पर नगण्य है।
स्टीव जेसोप

4
आपका शब्द सही अर्थ के बारे में पहले से ही अवगत किसी को समझ में आता है, लेकिन आसानी से लोगों को गुमराह करने के लिए सवाल पूछने की जरूरत है। "आकार () ... वेक्टर में दिए गए तत्वों की संख्या सम्मिलित करेगा" - केवल पहली बार उपयोग किए जाने वाले सत्य - यह आम तौर पर अनुरोधित संख्या और पूर्व-मौजूदा के बीच अंतर सम्मिलित करता है size()। "रिज़र्व () विधि केवल मेमोरी आवंटित करती है" - यह मेमोरी को आवंटित कर सकता है या नहीं यह इस पर निर्भर करता है कि क्या capacity()पहले से ही पर्याप्त है, इसके लिए तत्वों को स्थानांतरित करने और उनकी मूल मेमोरी को निपटाने की भी आवश्यकता हो सकती है। "आवंटन के एक जोड़े से बचना चाहते हैं" और प्रतियां आदि
टोनी डेलरॉय

19
दरअसल, धकेलने से पहले जलावन महत्वपूर्ण है और इसका उपयोग किया जाना चाहिए। मान लें कि आप किसी तरह के 3 डी मॉडल लोडर को कोड कर रहे हैं और मॉडल में 15000 कोने हैं। यदि आप पहले उन्हें पहले से आवंटित किए बिना लोड करते समय प्रत्येक शीर्ष पर पुश_बैक करने का प्रयास करते हैं, तो यह गंभीर समय लेगा। मैंने व्यक्तिगत रूप से अनुभव किया है कि, मैंने एक कार .obj मॉडल को 100000 कोने के साथ लोड करने की कोशिश की, इसमें 30 सेकंड का समय लगा। फिर मैंने .reserve () के साथ प्री-एलोकेशन का उपयोग करके कोड को रिफैक्ट किया, अब इसमें 3 सेकंड लगते हैं। कोड की शुरुआत में सिर्फ .reserve (100000) लगाकर 27 सेकंड बचाए गए।
डेनिज़

1
@ डिडिज 100000 पैमाने पर तुच्छ सच है, लेकिन 100-300 पैमाने पर बहुत सच नहीं है, जहां अनावश्यक रूप से किया जाए तो जलाशय बेकार हो सकता है।
डेवॉर्ड

30

resize()न केवल स्मृति आवंटित करता है, यह वांछित आकार के रूप में कई उदाहरण भी बनाता है जिसे आप तर्क के रूप में पास करते हैं। लेकिन केवल स्मृति आवंटित करता है, यह उदाहरण नहीं बनाता है। अर्थात्,resize()reserve()

std::vector<int> v1;
v1.resize(1000); //allocation + instance creation
cout <<(v1.size() == 1000)<< endl;   //prints 1
cout <<(v1.capacity()==1000)<< endl; //prints 1

std::vector<int> v2;
v2.reserve(1000); //only allocation
cout <<(v2.size() == 1000)<< endl;   //prints 0
cout <<(v2.capacity()==1000)<< endl; //prints 1

आउटपुट ( ऑनलाइन डेमो ):

1
1
0
1

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


6
करने के बाद reserve(N), हम operator []हानिरहित उपयोग कर सकते हैं । सही बात ?
.मिलिंद

2
हालांकि अधिकांश कार्यान्वयन आपके द्वारा अनुरोध की गई सटीक राशि का आवंटन करेंगे reserve, लेकिन विनिर्देशन में केवल इसके लिए कम से कम इतना ही आवंटित करने की आवश्यकता होती है, इसलिए कुछ कार्यान्वयन कुछ सीमा तक हो सकते हैं और इस प्रकार 1000 से अधिक क्षमता दिखा सकते हैं।
Jan Hudec

16
@iammilind: नहीं, यदि सूचकांक अधिक या बराबर है v.size()। ध्यान दें कि वेक्टर का reserve(N)परिवर्तन नहीं होता size()है।
नवाज

5
@iililind: सही। रीसर्व को कॉल करने के बाद, कोई प्रविष्टियाँ नहीं जोड़ी जाती हैं, केवल उन्हें जोड़ने के लिए पर्याप्त मेमोरी प्राप्त की जाती है।
जान हुदेक

2

आपके विवरण से, ऐसा लगता है कि आप वेक्टर t_Names के आवंटित भंडारण स्थान को "आरक्षित" करना चाहते हैं।

ध्यान दें कि resizeनए आवंटित वेक्टर को आरंभीकृत करें जहां reserveसिर्फ आवंटित करता है लेकिन निर्माण नहीं करता है। इसलिए, 'रिज़र्व' 'रिसाइज़' की तुलना में बहुत तेज़ है

आप आकार बदलने और आरक्षित करने के अंतर के बारे में प्रलेखन का उल्लेख कर सकते हैं


1
कृपया इसके बजाय यहां देखें: वेक्टर और क्षमता ( क्यों? )
13'11

1
लिंक जोड़ने के लिए धन्यवाद, sehe
डुबकी

2

आरक्षित करें जब आप नहीं चाहते कि आरक्षित होने पर ऑब्जेक्ट्स को इनिशियलाइज़ किया जाए। जब आप आकार बदलते हैं, तब आप तार्किक रूप से अंतर करना और उसकी गणना बनाम इसके उपयोग की संख्या को ट्रैक करना पसंद कर सकते हैं। इसलिए इंटरफ़ेस में एक व्यवहारिक अंतर है - वेक्टर आरक्षित होने पर समान तत्वों की संख्या का प्रतिनिधित्व करेगा, और आपके परिदृश्य में आकार बदलने पर 100 तत्व बड़ा होगा।

क्या इस तरह के परिदृश्य में कोई बेहतर विकल्प है?

यह पूरी तरह से आपके उद्देश्य पर निर्भर करता है कि कब डिफ़ॉल्ट व्यवहार से लड़ना है। कुछ लोग स्वनिर्धारित आबंटकों का पक्ष लेंगे - लेकिन हमें वास्तव में एक बेहतर विचार की आवश्यकता है कि आप जो भी कार्यक्रम कर रहे हैं वह आपको अच्छी तरह से सलाह देने के लिए हल करने का प्रयास कर रहा है।

fwiw, कई वेक्टर कार्यान्वयन बस आवंटित तत्व की संख्या को दोगुना कर देंगे जब उन्हें बढ़ना होगा - क्या आप चोटी के आवंटन के आकार को कम करने की कोशिश कर रहे हैं या आप कुछ लॉक फ्री प्रोग्राम या कुछ और के लिए पर्याप्त स्थान आरक्षित करने की कोशिश कर रहे हैं?


" आरक्षित करें जब आप नहीं चाहते कि आरक्षित होने पर ऑब्जेक्ट्स को इनिशियलाइज़ किया जाए। " सही फॉर्म्युलेशन वह है जब आप नहीं चाहते कि ऑब्जेक्ट्स मौजूद हों । यह एक तुच्छ रूप से रचनात्मक प्रकार के एक असिंचित सरणी की तरह नहीं है, जहाँ वस्तुओं को पढ़ा नहीं जा सकता है लेकिन उन्हें सौंपा जा सकता है; बल्कि, केवल स्मृति आरक्षित है, लेकिन इसमें कोई भी वस्तु मौजूद नहीं है, इसलिए उन्हें operator[]या किसी भी चीज का उपयोग नहीं किया जा सकता है ।
अंडरस्कोर_ड
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.