2012-09-23 18 views
14

एसटीएल कंटेनर एक कस्टम संभाजक चुना है के लिए एक टेम्पलेट पैरामीटर नहीं है। इसमें कुछ समय लगा, लेकिन मुझे लगता है कि मैं समझता हूं कि यह कैसे काम करता है। किसी भी तरह यह वास्तव में अच्छा नहीं है क्योंकि दिया गया आवंटक प्रकार सीधे उपयोग नहीं किया जाता है लेकिन यह किसी अन्य प्रकार के आवंटक के लिए रिबाउंड होता है। अंत में मैं इसके साथ काम कर सकता हूं।एसटीएल कंटेनर: निर्माता के संभाजक पैरामीटर और scoped allocators

API पढ़ने के बाद मैं मान्यता प्राप्त वहाँ भी है कि संभावना निर्माता पैरामीटर के रूप में allocators देने के लिए। लेकिन मुझे कैसे पता चलेगा कि किस प्रकार का आवंटक कंटेनर उपयोग करता है, अगर यह टेम्पलेट पैरामीटर से दिए गए आवंटक को आंतरिक रूप से पुनर्निर्मित करता है?

साथ ही मैंने पढ़ा है कि सी ++ 11 अब scoped allocators जो अपनी युक्त कंटेनरों के लिए एक कंटेनर की संभाजक का पुन: उपयोग करने की अनुमति का उपयोग करता है। स्कोप्ड आवंटक सक्षम कंटेनर का कार्यान्वयन लगभग उस व्यक्ति से अलग होता है जो स्कॉप्ड कंटेनरों से अवगत नहीं है?

दुर्भाग्य से मैं कुछ भी है कि इस समझा सकता है खोजने के लिए सक्षम नहीं था। उत्तर के लिए धन्यवाद!

उत्तर

13

लेकिन मुझे कैसे पता चलेगा कि कंटेनर किस प्रकार का आवंटक उपयोग करता है, अगर टेम्पलेट पैरामीटर से दिए गए आवंटक को आंतरिक रूप से पुनर्निर्मित करता है?

हमेशा निर्माता (जहां T कंटेनर के value_type है) के लिए एक Allocator<T> की आपूर्ति। कंटेनर इसे Allocator<U> में परिवर्तित कर देगा जहां U कंटेनर की कुछ आंतरिक डेटा संरचना है।Allocator ऐसे परिवर्तित कंस्ट्रक्टर्स की आपूर्ति करने के लिए आवश्यक है, उदा .:

template <class T> class allocator { 
    ... 
    template <class U> allocator(const allocator<U>&); 

साथ ही मैंने पढ़ा है कि सी ++ 11 अब scoped allocators जो अपने युक्त कंटेनरों के लिए एक कंटेनर की संभाजक का पुन: उपयोग करने की अनुमति का उपयोग करता है।

ठीक है, और अधिक सटीक होना करने के लिए, सी ++ 11 एक संभाजक एडाप्टरscoped_allocator_adaptor कहा जाता है:

template <class OuterAlloc, class... InnerAllocs> 
class scoped_allocator_adaptor : public OuterAlloc 
{ 
    ... 
}; 

से सी ++ 11:

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

तो तुम केवल scoped allocators व्यवहार करता है, तो आप अपने कंटेनर के लिए संभाजक के रूप में एक scoped_allocator_adaptor निर्दिष्ट मिलता है।

स्कॉप्ड आवंटक सक्षम कंटेनर का कार्यान्वयन कैसे किया जाता है जो स्कॉप्ड कंटेनरों से अवगत नहीं है?

कुंजी यह है कि कंटेनर अब आवंटक से निपटने के बजाय allocator_traits नामक एक नई कक्षा के माध्यम से अपने आवंटक से संबंधित है। और कंटेनर इस तरह के निर्माण और कंटेनर में value_type रों destructing के रूप में कुछ कार्यों के लिए allocator_traits उपयोग करना चाहिए। कंटेनर सीधे आवंटक से बात नहीं करनी चाहिए।

उदाहरण के लिए, allocators उपलब्ध करा सकता है एक सदस्य construct कि एक निश्चित पते पर एक प्रकार का निर्माण दिए गए तर्कों का उपयोग होगा बुलाया:

template <class T> class Allocator { 
    ... 
    template<class U, class... Args> 
     void construct(U* p, Args&&... args); 
}; 

एक संभाजक इस सदस्य प्रदान नहीं करता है, allocator_traits एक प्रदान करेगा डिफ़ॉल्ट कार्यान्वयन। किसी भी घटना में, कंटेनर का निर्माण करना चाहिए इस construct समारोह का उपयोग करके सभी value_type है, लेकिन allocator_traits के माध्यम से उपयोग कर, और का उपयोग नहीं कर allocator सीधे:

allocator_traits<allocator_type>::construct(the_allocator, *ugly details*); 

scoped_allocator_adaptor कस्टम construct कार्य करता है जो करने के लिए जो allocator_traits अग्रेषित करेंगे प्रदान करता है uses_allocator लक्षणों का लाभ उठाएं और सही आवंटक को value_type कन्स्ट्रक्टर के साथ पास करें। कंटेनर इन विवरणों के आनंद से अनजान रहता है। कंटेनर को केवल यह पता होना चाहिए कि allocator_traits construct फ़ंक्शन का उपयोग करके इसे value_type बनाना होगा।

कंटेनर को स्टेटस आवंटकों को सही ढंग से संभालने के लिए निपटने के लिए अधिक जानकारी होनी चाहिए। हालांकि कंटेनर को कोई धारणा नहीं होने के कारण इन विवरणों का भी निपटारा किया जाता है लेकिन allocator_traits के माध्यम से सभी गुण और व्यवहार प्राप्त करते हैं। कंटेनर यह भी नहीं मान सकता कि pointerT* है। इसके बजाय allocator_traits पूछकर यह प्रकार मिलता है।

संक्षेप में, सी ++ 11 कंटेनर बनाने के लिए, allocator_traits पर अध्ययन करें। और फिर जब आप अपने ग्राहक scoped_allocator_adaptor का उपयोग करते हैं तो आपको स्कोप्ड आवंटन व्यवहार मुफ्त में मिलता है।

4

एक कंटेनर द्वारा प्रयोग किया जाता संभाजक के प्रकार अपने निर्माता तर्क द्वारा परिभाषित किया गया है: यह वास्तव में इस प्रकार के जो कंटेनर के कन्स्ट्रक्टर्स में होने की उम्मीद कर रहा है। हालांकि, किसी भी आवंटक को इसके लिए परिभाषित किए गए विभिन्न प्रकार की सेवा करने में सक्षम होना चाहिए। उदाहरण के लिए, std::list<T, A> के लिए आवंटित आवंटन T ऑब्जेक्ट आवंटित करने में सक्षम है लेकिन इसका उपयोग कभी भी इन ऑब्जेक्ट को आवंटित करने के लिए नहीं किया जाएगा क्योंकि std::list<T, A> को वास्तव में नोड्स आवंटित करने की आवश्यकता है। यही है, आवंटक एक अलग प्रकार आवंटित करने के लिए वापसी होगी। दुर्भाग्यवश, यह एक विशिष्ट प्रकार की सेवा के लिए आवंटक का उपयोग करना मुश्किल बनाता है: आप नहीं जानते कि आवंटक वास्तव में किस तरह से काम करेगा। कंटेनर निर्धारित करता है कि यह एक निर्माता एक मिलान संभाजक लेने के साथ किसी भी सदस्य हैं:

scoped allocators यह काफी सीधे आगे काम करता है के संबंध में

। यदि ऐसा है, तो यह उपयोग किए गए आवंटक को पुनर्जीवित करेगा और सदस्य को इस आवंटक को पास करेगा। यह स्पष्ट नहीं है कि तर्क यह निर्धारित करता है कि आवंटन का उपयोग किया जा रहा है या नहीं। यह निर्धारित करने के लिए कि कोई सदस्य आवंटक का उपयोग करता है, गुण std::uses_allocator<T, A> का उपयोग किया जाता है: यह निर्धारित करता है कि T में नेस्टेड typedef allocator_type है और यदि A इस प्रकार में परिवर्तित किया जा सकता है। सदस्य वस्तुओं के निर्माण के लिए नियम 20.6.7.2 [allocator.uses.construction] में वर्णित हैं।

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

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