2010-04-23 15 views
8

मैं अपनी सटीक आकार की क्षमता को कम करने के लिए std::vector को 'सिकुंक-टू-फिट' करना चाहता हूं, ताकि अतिरिक्त मेमोरी मुक्त हो। मानक चाल एक वर्णित here हो रहा है:स्मृति-कुशल तरीके से std :: vector को फिट करने के लिए कैसे करें?

template< typename T, class Allocator > 
void shrink_capacity(std::vector<T,Allocator>& v) 
{ 
    std::vector<T,Allocator>(v.begin(),v.end()).swap(v); 
} 

का हटना करने के लिए फिट स्मृति को बचाने के लिए है पूरे मुद्दे हैं, लेकिन इस विधि पहले एक गहरी प्रतिलिपि पैदा नहीं करता और फिर उदाहरणों स्वैप? तो किसी बिंदु पर - जब प्रतिलिपि बनाई जाती है - स्मृति उपयोग दोगुनी हो जाती है?

यदि ऐसा है, तो क्या कम करने के लिए एक और स्मृति-अनुकूल तरीका है? (मेरे मामले में वेक्टर वास्तव में बड़ा है और मैं मूल रूप से किसी भी समय मेमोरी में इसकी प्रतिलिपि नहीं ले सकता।)

+0

डुप्लिकेट ?: http://stackoverflow.com/questions/1111078/reduce-the-capacity-of-an-stl-vector – ergosys

+2

वास्तव में, वह स्मृति में दोनों वस्तुओं की अस्थायी प्रति को रोकना नहीं चाहता समय जब स्वैप हो रहा है। –

+0

असल में, यही सवाल भी है (प्रतिलिपि से परहेज)। लिंक के लिए धन्यवाद। – Frank

उत्तर

3

ठीक है, अगर आप किसी सरणी का आकार बदलना चाहते हैं, तो आप क्या करेंगे? आपको एक नया निर्माण करना होगा और सभी मानों को प्रतिलिपि बनाना होगा - इसे व्यक्तिगत रूप से या memcpy या जो कुछ भी हो। आप वास्तव में सी या सी ++ में किसी सरणी का आकार बदल नहीं सकते हैं।

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

आप सकता है, सिद्धांत रूप में, एक shrink_capacity() समारोह जो सच है कि आप अस्थायी रूप से कम या ज्यादा डबल इसके आकार आवश्यकताओं, लेकिन जब से std::vector वर्तमान में इस तरह के एक समारोह नहीं है के लिए था कि, आप वास्तव में एक स्पष्ट प्रतिलिपि बनाने के लिए है छिपा रखा है । स्वैप चाल ऐसा करने का एक अच्छा तरीका है।

यदि आप वास्तव में इस तरह के मामले में स्मृति की परवाह करते हैं, तो आप वेक्टर को सीधे ऑब्जेक्ट्स रखने के बजाय पॉइंटर्स (या स्मार्ट पॉइंटर्स) का उपयोग कर सकते हैं। यह पूरी तरह से वांछनीय नहीं हो सकता है, लेकिन यह आपकी स्मृति आवश्यकताओं को कम करेगा।

+0

क्यों नहीं कर सकते :: वेक्टर बस मॉलोक (या नया) बताता है कि इसे अंतिम प्रविष्टि से आरक्षित आकार में स्मृति की आवश्यकता नहीं है? फिर ढेर आवंटक इसे वापस मुफ्त सूची में डाल सकता है - –

+1

@ मार्टिन की प्रतिलिपि बनाने की कोई आवश्यकता नहीं है मैंने ऐसा करने के किसी भी तरीके से कभी नहीं सुना है।वहाँ realloc है, लेकिन चूंकि इसकी कोई गारंटी नहीं है कि यह स्मृति के एक ही ब्लॉक को वापस करने जा रहा है, आप पहले से ही सरणी में जो भी खो देते हैं। अगर ऐसा करने का कोई तरीका है, तो मुझे लगता है कि वेक्टर ऐसा कर सकता है, लेकिन वर्तमान में ऐसा कोई फ़ंक्शन नहीं है, यहां तक ​​कि यह संभव है। –

+5

क्योंकि अधिकांश स्मृति आवंटक इस तरह से काम नहीं करते हैं; आप पहले से आवंटित ब्लॉक के सीमा टैग को संपादित नहीं कर सकते हैं ताकि इसे मुक्त सूची में वापस ढेर करते समय इसे छोटा बना दिया जा सके। कुछ विदेशी आवंटक यह कर सकते हैं, लेकिन मानक पुस्तकालय उन पर निर्भर करने के लिए डिज़ाइन नहीं किया गया है। – Crashworks

-1

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

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

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