2011-02-04 7 views
6

क्या कोई एसटीएल कार्यान्वयन के बारे में जानता है जो गतिशील आवंटकों को उपयोग से पहले एक कंटेनर के उदाहरण में पारित करने की अनुमति देता है।एक एसटीएल कार्यान्वयन जो एक गतिशील/राज्य आधारित आवंटक का उपयोग करता है?

परिदृश्य यह है कि हमारे पास एक सामान्य स्मृति आवंटक है जो स्मृति के कई पूल प्रबंधित करता है और कहने के प्रत्येक उदाहरण के लिए stl :: वेक्टर हम स्मृति के एक अलग पूल से प्रत्येक उदाहरण आवंटित करना चाहते हैं।

मानक एसटीएल कार्यान्वयन के साथ समस्या यह है कि आप केवल एक प्रकार के आधार पर मेमोरी पूल को परिभाषित कर सकते हैं यानी सभी वेक्टर प्रकार के int उसी पूल से आवंटित किए जाएंगे।

मैंने पहले से ही हमारे डिफ़ॉल्ट stl :: आवंटक को एक ऐसे राज्य के लिए बदल दिया है जिसमें एक राज्य यानी पूल है जिसे हम इस आवंटन को आवंटित करना चाहते हैं लेकिन यह stl :: सूची कहने के लिए अच्छा काम नहीं करता है, जहां यह चीजों को आवंटित करता है डिफ़ॉल्ट सीटीओआर।

हमारी लाइब्रेरी से संबंधित कारणों के लिए हमारे पास सभी ऑब्जेक्ट्स के लिए सीटीआर में एक वैध पूल नहीं है और इसलिए हम एसएलएल कंटेनर का उपयोग करने से पहले 'सेट मेमोरी पूल' फ़ंक्शन को कॉल करना चाहते हैं।

क्या कोई इस तरह की चीज का समर्थन करने वाले कार्यान्वयन में आया है?

+0

क्या माइक्रोसॉफ्ट एसटीएल है जो अपने कन्स्ट्रक्टर में सूची के मुख्य नोड को आवंटित करता है? आदर्श एसटीएल कार्यान्वयन (जीएनयू पढ़ें) रिक्त कंटेनरों का निर्माण करते समय किसी स्मृति आवंटन का उपयोग नहीं करेगा। –

+0

यूप दोनों माइक्रोसॉफ्ट और मेरे जीएनयू पोर्ट (सर्का जीसीसी 3.4.1) दोनों सीटीआर में हेड नोड आवंटित करते हैं। दूसरी तरफ एसटीएलपोर्ट मेरी आवश्यकताओं का समर्थन नहीं करता है और पूर्ण उदाहरण स्रोत के लिए मेरा जवाब देखता है। – user176168

उत्तर

2

टाइप किए गए आवंटक आवंटन करने के लिए नीचे एक सामान्य आवंटक का उपयोग कर सकते हैं।

संभाजक इन कार्यों का समर्थन करने की जरूरत है:

pointer address (reference x) const; 
    const_pointer address (const_reference x) const; 
    pointer allocate (size_type n, allocator<void>::const_pointer hint=0); 
    void deallocate (pointer p, size_type n); 
    size_type max_size() const throw(); 
    void construct (pointer p, const_reference val); 

मान लें कि आप एक तंत्र है कि बस स्मृति आवंटित करता है और स्मृति deallocates है, तो आप का उपयोग करें ऊपर कार्यों में से कुछ को लागू कर सकते हैं।

टाइप किए गए आवंटकों का लाभ यह है कि आप जानते हैं कि आप बिल्कुल उसी आकार के बहुत सारे आइटम बनाने जा रहे हैं और इसलिए फिट करने के लिए अपने "पेज" बना सकते हैं। सबसे बड़ा मुद्दा यह हो सकता है कि आपको आवंटित बफर (और वास्तव में वेक्टर की जरूरत है) वापस करने के लिए आवंटित() द्वारा मजबूर किया जाता है।

http://www.cplusplus.com/reference/std/memory/allocator/

आपका प्रश्न अभी भी थोड़ा के रूप में यह क्यों पर्याप्त नहीं है करने के लिए स्पष्ट नहीं है। आप "एक बार" तर्क के साथ मेमोरी पूल शुरू कर सकते हैं। (यदि यह बहु-थ्रेडेड है तो आप इसे प्राप्त करने के लिए बूस्ट :: एक बार उपयोग कर सकते हैं)।

+0

मन भी रखें कि यदि आप एक ही संभाजक के कई अलग उदाहरणों चाहते हैं, और यह काफी बस संकलन समय पर उनके बीच स्विच करने के लिए अच्छा है, तो आप भी एक टेम्प्लेटेड संभाजक के लिए एक पूर्णांक या टैग प्रकार तर्क पारित कर सकते हैं। – bdonlan

0

एक विकल्प थ्रेड-लोकल वैरिएबल का उपयोग करने के लिए पॉइंटर को मेमोरी पूल में उपयोग करने के लिए और आपके आवंटन कार्यान्वयन में इसे कैप्चर करने के लिए होगा। उदाहरण के लिए (boost::thread_specific_ptr उपयोग करते हुए):

// Global variable 
boost::thread_specific_ptr<allocator_impl> real_allocator; 

struct set_allocator : boost::noncopyable { 
private: 
    allocator_impl *old; 
public: 
    set_allocator(allocator_impl *newAllocator) { 
     old = real_allocator.get(); 
     real_allocator.reset(newAllocator); 
    } 
    ~set_allocator() { 
     real_allocator.reset(old); 
    } 
}; 

template<typename T> 
struct myallocator { 
private: 
    real_allocator *delegate; 
public: 
    myallocator() { 
     delegate = real_allocator.get(); 
    } 
    T *allocate(size_t n, allocator<void>::const_pointer hint=0) 
    { 
     return delegate->allocate(sizeof(T), n, hint); 
    } 
    // Other mandatory STL Allocator functions and typedefs follow 
}; 

// later: 
allocator_impl *allocator = new allocator_impl(); 
set_allocator sa(allocator); // Set current allocator using RAII 
std::list<int, myallocator> mylist; // using *allocator as the backing allocator 

एपीआई कि myallocator को लागू करना चाहिए वर्णन किया गया है here

दुर्भाग्य से, एसटीएल एपीआई में सीमाओं के कारण, यह उतना ही अच्छा है जितना आप एसटीएल को पुन: कार्यान्वित किए बिना प्राप्त कर सकते हैं। हालांकि, तीसरे पक्ष के पुस्तकालय हो सकते हैं जो आपको ऑब्जेक्ट के कन्स्ट्रक्टर को कहीं भी आवंटित करने देते हैं।

1

मानक एसटीएल के साथ समस्या यह कार्यान्वयन है कि आप केवल एक प्रकार आधार यानी सभी वेक्टर प्रकार int के एक ही पूल से आवंटित हैं उस पर स्मृति पूल को परिभाषित कर सकते हैं।

यही सच नहीं है। आपके पास int तत्व रखने वाले विभिन्न वैक्टर हो सकते हैं जिनमें प्रत्येक एक अलग आवंटक प्रकार होता है।

हालांकि

, प्रश्न के बारे में -

किसी को भी एक एसटीएल कार्यान्वयन गतिशील allocators के लिए उपयोग करने से पहले एक कंटेनर का एक उदाहरण के लिए में पारित होने की अनुमति देता है कि पता है।

- इसलिए यह सी ++ मानक लाइब्रेरी (एसटीएल) द्वारा समर्थित नहीं है, हालांकि यह हो सकता है कि प्रति-ऑब्जेक्ट आवंटकों का कार्य करने पर कार्यान्वयन हो, यह पोर्टेबल नहीं है।

क्यों और कैसे कस्टम allocators उपयोग करने के लिए की एक विस्तृत विश्लेषण के लिए Scott Meyers's पुस्तक Effective STL, विशेष रूप से आइटम 11 देखें: कस्टम allocators के वैध का उपयोग को समझें।

4

मैं आपके सवाल का ठीक बारे में इतना यकीन नहीं कर रहा हूँ। तो मैं एक राज्य पूर्ण आवंटक के मामले को कवर करेंगे।

सी में 03 ++, किसी भी संभाजक ऐसी ही दूसरी संभाजक द्वारा आबंटित संसाधनों पुनःआवंटन में सक्षम होना चाहिए।

C++ 0x मानक वास्तव में इस सीमा को हटा दिया और राज्य के पूर्ण allocators जब तक वे संभाजक वाकिफ कंटेनर (मुझे लगता है कि सभी कंटेनर एसटीएल के साथ पैक को शामिल किया गया है, क्योंकि वे कर रहे हैं एसटीएल कंटेनरों को पास करने की अनुमति देता है मॉडल अनुक्रम)।

उदाहरण के लिए: [allocator.adaptor] $20.10 Class scoped_allocator अब C++ 0x एसटीएल का हिस्सा है।

0

ठीक है तो एसटीएल बंदरगाह इस तरह की कार्यक्षमता का समर्थन करता प्रतीत होता है, जहां माइक्रोसॉफ्ट (वीएस 2008) और जीएनयू कार्यान्वयन (एसएलएल सीआरसी जीसीसी 3.4.1 का एक बंदरगाह) नहीं है क्योंकि वे चीजों को आवंटित/हटाते हैं ctors/dtors।

यहाँ अपने परीक्षण ऐसा करने के तरीके दिखा कोड है। चेतावनी यह किसी भी माध्यम से पूर्ण कार्यान्वयन नहीं है!

#include <list> 
#include <assert.h> 

namespace my 
{ 

class memory_pool 
{ 
public: 
    memory_pool() : m_top(0){}; 
    ~memory_pool(){}; 

    void* alloc(int size, int align) { void* p = (void*)&m_pool[m_top]; m_top += size; return p; } 
    void free (void* p) { assert((p >= m_pool) && (p < &m_pool[m_top])); } 
private: 
    char m_pool[0xFFFF]; 
    int m_top; 
}; 

template<class T> 
class dynamic_allocator 
{ 
    template<typename U> friend class dynamic_allocator; 
public: 
    typedef T     value_type;   
    typedef size_t    size_type;   
    typedef value_type*   pointer;    
    template <class _Tp1> struct rebind { typedef dynamic_allocator<_Tp1> other; }; 

    dynamic_allocator() : m_pPool(NULL){} 
    dynamic_allocator(memory_pool* pPool){ m_pPool = pPool; } 
    dynamic_allocator(const dynamic_allocator<T>& alloc) : m_pPool(alloc.m_pPool){} 
    template< typename U > 
    dynamic_allocator(const dynamic_allocator<U>& alloc) : m_pPool(alloc.m_pPool){} 
    ~dynamic_allocator() {} 

    pointer allocate(size_type count){ return allocate(count, NULL); } 
    pointer allocate(size_type count, const void*) { assert(m_pPool); return (pointer)m_pPool->alloc(count * sizeof(T), __alignof(T)); } 
    void deallocate(pointer p, size_type count) { assert(m_pPool); m_pPool->free(p); } 

    void set(memory_pool* pPool) { m_pPool = pPool; } 

private: 
    memory_pool* m_pPool; 
}; 

template< typename T, typename Al = dynamic_allocator<T> > 
class list : public std::list<T, Al> 
{ 
public: 
    typedef typename std::list<T, Al>::allocator_type allocator_type; 

    list() : std::list<T, Al>(){}; 
    list(const allocator_type& a) : std::list<T, Al>(a){}; 
    ~list(){}; 

    void initialise(memory_pool& pool){ std::list<T, Al>::_M_node.set(&pool); } // or something like this 
    void terminate(void){ clear(); std::list<T, Al>::_M_node.set(NULL); }     // or something like this 
}; 

}; // namespace my 

class lemon 
{ 
public: 
    lemon(){}  // must be empty ctor as we don't want to have active mem pool in ctor for users to use 
    ~lemon(){} 

    void initialise(my::memory_pool& pool){ m_list.initialise(pool); } 
    void terminate(void)     { m_list.terminate(); } 

    void add(float f) { m_list.push_back(f); } 

private: 
    my::list<float> m_list; 
}; 

int main(void) 
{ 
    my::memory_pool poolA; 
    my::memory_pool poolB; 

    my::dynamic_allocator<float> aa(&poolA); 
    my::list<float> a(aa); 
    my::list<float> fail; 

    std::list<float>::allocator_type bb; 
    std::list<float> b(bb); 

    a.push_back(0.2f); 
    b.push_back(50.0f); 
    //fail.push_back(19.0f); 

    a.clear(); 
    b.clear(); 

    lemon lemons[2]; 

    lemons[0].initialise(poolA); 
    lemons[1].initialise(poolB); 

    lemons[0].add(10.0f); 
    lemons[1].add(20.0f); 
    lemons[1].add(18.0f); 

    lemons[0].terminate(); 
    lemons[1].terminate(); 

    scanf("press any key\n"); 

    return 0; 
}