2010-06-23 12 views
31

सी में मानक मेमोरी हैंडलिंग फ़ंक्शंस malloc(), realloc() और free() हैं। हालांकि, सी ++ stdlib आवंटकों में से केवल दो समानांतर: कोई पुनर्विक्रय कार्य नहीं है। बेशक, realloc() जैसा बिल्कुल करना संभव नहीं होगा, क्योंकि स्मृति की प्रतिलिपि बनाना गैर-समग्र प्रकारों के लिए उपयुक्त नहीं है। लेकिन वहाँ के साथ, कहते हैं, इस समारोह एक समस्या हो जाएगा:सी ++ आवंटकों में कोई पुनर्वितरण कार्यक्षमता क्यों नहीं है?

bool reallocate (pointer ptr, size_type num_now, size_type num_requested); 

जहां

  • ptr पहले num_now की वस्तुओं की संभाजक साथ आवंटित किया जाता है;
  • num_requested> = num_now;

और शब्दों को इस प्रकार है:

  • अगर संभाजक स्मृति ब्लॉक ptr पर आकार से num_now वस्तुओं के लिए num_requested वस्तुओं को दी विस्तार कर सकते हैं, यह बहुत (अतिरिक्त मेमोरी छोड़ने अप्रारंभीकृत) करता है और true रिटर्न;
  • अन्यथा यह कुछ भी नहीं करता है और false देता है।

माना जाता है कि यह बहुत आसान नहीं है, लेकिन जैसा कि मैं समझता हूं, आवंटक, ज्यादातर कंटेनरों और कंटेनर कोड के लिए पहले से ही जटिल हैं।

को देखते हुए इस तरह के एक समारोह, std::vector, कहते हैं, के रूप में (स्यूडोकोड) इस प्रकार हो जाना सकता है:

if (allocator.reallocate (buffer, capacity, new_capacity)) 
    capacity = new_capacity;  // That's all we need to do 
else 
    ... // Do the standard reallocation by using a different buffer, 
     // copying data and freeing the current one 

Allocators कि पूरी तरह से बदल रहा स्मृति आकार के काबिल नहीं हैं सिर्फ बिना शर्त return false; द्वारा इस तरह के एक समारोह को लागू कर सकते हैं।

क्या वहां कुछ कम पुनर्वितरण-सक्षम आवंटन कार्यान्वयन है जो परेशान करने के लायक नहीं होगा? या क्या कुछ समस्याएं हैं जिन्हें मैंने अनदेखा किया?

+13

+1, यह एक सवाल है जो हमेशा मुझे खराब करता है। –

+0

स्ट्रॉस्ट्रप इस चीज़ पर लेते हैं: http://www2.research.att.com/~bs/bs_faq2.html#renew; यह समस्या को वेक्टर की आंतरिक कार्यप्रणाली में प्रस्तुत करता है, लेकिन यह नहीं कहता कि सरणी को बढ़ाना आसान बनाने के लिए "नवीकरण" जैसी कोई तंत्र क्यों नहीं है। –

+1

कुछ मामलों में ऐसा करने से 'std :: vector' को रोकना कुछ भी नहीं है (उदा।, यह मानक आवंटक का उपयोग करके जानता है)। मानक पुस्तकालय को अंतर्निहित प्रणाली के ज्ञान का उपयोग करने की अनुमति है। – KeithB

उत्तर

17

से: http://www.sgi.com/tech/stl/alloc.html

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

दुर्भाग्य से, यह सी पुस्तकालय से realloc की निषिद्ध उपयोग होगा। बदले में यह जटिलता को कई आवंटकों कार्यान्वयन में जोड़ा होगा, और मेमोरी-डीबगिंग उपकरण के साथ बातचीत को और अधिक कठिन बना दिया होगा। इस प्रकार हमने इस विकल्प के खिलाफ का निर्णय लिया।

+2

मुझे लगता है कि यह एक शर्म की बात है कि उन्होंने कम से कम आवंटक के इंटरफ़ेस को रीयलोकेट विधि नहीं जोड़ा। इसे केवल मौजूदा ब्लॉक को मुक्त करने और एक नया आवंटित करने के लिए लागू किया जा सकता था, लेकिन यह आवंटन इंटरफ़ेस का उपयोग करके सभी कोड को दोबारा बिना दोबारा लागू करने की क्षमता प्रदान करता। – stinky472

1

मुझे लगता है कि यह उन चीजों में से एक है जहां भगवान गलत थे, लेकिन मैं मानक समिति को लिखने के लिए बहुत आलसी था।

वहाँ सरणी आवंटन के लिए एक realloc किया जाना चाहिए था:

p = renew(p) [128];

या ऐसा ही कुछ।

+0

यदि आप सरणी के बजाय वैक्टर का उपयोग करते हैं, तो '.reserve()' है। वेक्टर आमतौर पर बेहतर होने पर सरणी के लिए नई कार्यक्षमता क्यों जोड़ते हैं? –

+1

@ डेविड थॉर्नले, हुड के नीचे वाले वैक्टरों को आवंटक इंटरफ़ेस से गुज़रना पड़ता है। तो ऐसा लगता है कि एक वेक्टर अप्रयुक्त स्मृति को यथासंभव कुशलता से मुक्त नहीं कर सकता है। (लेकिन मुझे लगता है/उम्मीद है कि मैं यहाँ कुछ याद कर रहा हूँ!) –

+1

@ डेविड थॉर्नले - बिल्कुल हारून ने क्या कहा। _Everyone_ कहता है "'वेक्टर' का उपयोग करें" - लेकिन वे अमूर्तता के गलत स्तर पर बात कर रहे हैं! 'वेक्टर' को स्वयं को निम्न स्तर आवंटन दिनचर्या पर बनाया जाना चाहिए (और वास्तव में बनाया गया है) जो आपको अनियमित स्मृति प्राप्त करने देता है और इसी तरह। यदि वे दिनचर्या निम्न स्तर के "पुनर्वितरण" फ़ंक्शन की पेशकश नहीं करते हैं, तो निश्चित रूप से 'वेक्टर' या तो नहीं हो सकता है। बेशक, यह 'आकार बदलें' और 'पुनर्विक्रेता' और अन्य सभी चीज़ों की पेशकश कर सकता है, लेकिन कवर के तहत वे केवल नए ब्लॉक आवंटित कर रहे हैं और चीजों की प्रतिलिपि बना रहे हैं। मौजूदा ब्लॉक का विस्तार करने की तरह कुछ भी नहीं। – BeeOnRope

3

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

+1

मुझे यकीन नहीं है कि मैं सहमत हूं कि उन्होंने ओओपी की वजह से इसके बारे में सोचा था। नियुक्ति नया विशेष रूप से वस्तुओं के स्मृति प्रबंधन के लिए एक सुविधा का एक उदाहरण है। –

+0

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

+0

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

8

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

+0

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

+1

@doublep: यदि आप स्पैस कंटेनर चाहते थे तो न तो (गतिशील रूप से) आवंटित सरणी और न ही वेक्टर वे हैं जो आप चाहते हैं। –

+0

@ मार्टिन यॉर्क: ठीक है, उदाहरण के लिए, Google स्पैरशैश लाइब्रेरी गतिशील रूप से आवंटित सरणी का उपयोग करती है और बहुत अच्छे परिणाम प्राप्त करती है। – doublep

11

यह वास्तव में एक डिजाइन दोष है कि Alexandrescu मानक allocators साथ बताते है (नहीं ऑपरेटर नई []/हटाने [] लेकिन क्या मूल रूप से एसटीएल std :: वेक्टर, उदा लागू करने के लिए इस्तेमाल किया allocators थे)।

एक realloc एक malloc, memcpy, और मुफ्त से काफी तेजी से हो सकता है। हालांकि, वास्तविक स्मृति ब्लॉक का आकार बदल सकता है, लेकिन यह स्मृति को एक नए स्थान पर भी ले जा सकता है। बाद के मामले में, यदि स्मृति ब्लॉक में गैर-पीओडी होते हैं, तो सभी वस्तुओं को नष्ट करने की आवश्यकता होगी और पुनर्विक्रय के बाद प्रतिलिपि बनाई जाएगी।

मुख्य बात मानक पुस्तकालय एक संभावना के रूप में इस को समायोजित करने की जरूरत है मानक संभाजक के सार्वजनिक इंटरफेस के हिस्से के रूप में एक पुनः आवंटित कार्य है। Std :: वेक्टर जैसी कक्षा निश्चित रूप से इसका उपयोग कर सकती है भले ही डिफ़ॉल्ट कार्यान्वयन नए आकार के ब्लॉक को मॉलोक करना और पुराने को मुक्त करना है। इसे एक ऐसा फ़ंक्शन होना आवश्यक है जो स्मृति में ऑब्जेक्ट्स को नष्ट करने और प्रतिलिपि बनाने में सक्षम है, हालांकि यह स्मृति को अपारदर्शी फैशन में नहीं मान सकता है। वहाँ एक छोटी जटिलता शामिल है और कुछ और टेम्पलेट काम की आवश्यकता होगी, जिसके कारण यह मानक पुस्तकालय से छोड़ा गया था।

std :: वेक्टर < ...> :: आरक्षित पर्याप्त नहीं है: यह एक अलग मामले को संबोधित करता है जहां कंटेनर का आकार अनुमान लगाया जा सकता है। वास्तव में परिवर्तनीय आकार की सूचियों के लिए, एक रीयलोक समाधान std :: वेक्टर जैसे संगत कंटेनर को बहुत तेज बना सकता है, विशेष रूप से यदि यह रीयलॉक मामलों से निपट सकता है जहां मेमोरी ब्लॉक को बिना किसी स्थानांतरित किए सफलतापूर्वक आकार दिया गया था, तो इस मामले में यह कॉलिंग प्रति को छोड़ सकता है स्मृति में वस्तुओं के लिए रचनाकार और विनाशक।

+1

+1 बैकअप के लिए एक लिंक: http://www.stepanovpapers.com/notes.pdf –

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