2011-02-04 2 views
6

동적 할당자를 사용하기 전에 컨테이너의 인스턴스에 전달할 수있는 STL 구현을 아는 사람이 있습니까?동적/상태 기반 할당자를 사용하는 STL 구현은 무엇입니까?

우리는 많은 메모리 풀을 관리하는 일반 메모리 할당 기가 있으며 stl :: vector의 각 인스턴스에 대해 서로 다른 메모리 풀에서 각 인스턴스를 할당하려고합니다.

표준 STL 구현의 문제는 유형 기반으로 메모리 풀을 정의 할 수 있다는 것입니다. 즉, int 유형의 모든 벡터는 동일한 풀에서 할당합니다.

이미 상태가 할당 된 풀에 대해 기본 stl :: allocator를 스왑 아웃했습니다.하지만이 인스턴스를 할당하려는 풀은 stl :: list에 잘 할당되지 않습니다. 디폴트의 ​​ctor

우리 도서관과 관련된 이유로 우리는 모든 객체에 대한 유효한 풀을 ctor에 가지고 있지 않으므로 사용자가 stl 컨테이너를 사용하기 전에 '메모리 풀 설정'함수를 호출하려고합니다.

누구나 이런 종류의 것을 지원하는 구현을 발견 했습니까?

+0

해당 생성자에서 목록의 헤드 노드를 할당하는 Microsoft STL입니까? 이상적인 STL 구현 (GNU 읽기)은 빈 컨테이너를 만들 때 메모리 할당을 사용하지 않습니다. –

+0

모두 마이크로 소프트와 내 GNU 포트 (gcc 3.4.1 참조)는 모두 ctor에 헤드 노드를 할당합니다. STLPort 다른 한편으로하지 않습니다 그리고 그래서 내 요구 사항을 지원하는 전체 예제 소스에 대한 내 대답을 참조하십시오. – 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); 

그냥 메모리를 할당하고 메모리 할당을 해제하는 메커니즘을 가정하면, 위의 일부 기능을 구현하기 위해 그것을 사용할 수 있습니다.

할당 자의 이점은 정확하게 동일한 크기의 항목을 많이 만들 예정이므로 "페이지"를 만들 수 있다는 것입니다. 가장 큰 문제는 allocate()가 인접한 버퍼를 반환하도록 강제되었다는 것입니다 (실제로 벡터에 필요합니다).

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

귀하의 질문은 여전히이 충분하지 않은 이유에 조금 불분명하다. "한 번"논리로 메모리 풀을 초기화 할 수 있습니다. (멀티 스레드 인 경우 boost :: once를 사용하여이를 수행 할 수 있습니다).

+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을 설명 구현해야하는 API를.

STL API의 제한 사항으로 인해 STL을 다시 구현하지 않으면 얻을 수있는 것처럼 좋습니다. 그러나 어딘가에있는 객체 생성자에 할당자를 전달할 수있는 써드 파티 라이브러리가있을 수 있습니다.

1

표준 STL의 문제는 구현 만 int 형의 즉, 모든 벡터의이 동일한 풀에서 할당 할 타입으로 메모리 풀을 정의 할 수 있다는 것입니다.

이것은 사실이 아닙니다. int 요소를 보유하는 다른 벡터가 각각 다른 할당 자 유형을 가질 수 있습니다. 질문에 대한 그러나

-

아무도 동적 할당 자 사용하기 전에 용기의 인스턴스에 전달 할 수있는 STL 구현을 알고 있나요.

- 이는 C++ 표준 라이브러리 (STL)에서 지원되지 않으므로 개체 단위 할당자가 작동하는 구현이있을 수 있지만 이식 가능하지는 않습니다. 사용자 정의 할당자를 사용하는 이유와 방법에 대한 자세한 분석을 위해

는 특히 항목 11 Scott Meyers'sEffective STL를 참조하십시오 : 사용자 정의 할당 자의 합법적 사용을 이해합니다.

4

귀하의 질문에 대해 확실하지 않습니다. 따라서 전체 할당 자의 경우를 다룰 것입니다.

C++ 03에서 모든 할당자는 동일한 유형의 다른 할당자가 할당 한 리소스를 할당 해제 할 수 있어야합니다.

는 C + +0 표준은 실제로 이러한 제한을 제거하고 국가 전체 할당 자만큼 그들이 할당 자 인식 컨테이너 (나는 그들이 있기 때문에, 그것은 STL과 함께 패키지 모든 컨테이너를 다루고 생각만큼 STL 컨테이너에 전달 될 수 있습니다

모델 시퀀스).

예 : [allocator.adaptor] $20.10 Class scoped_allocator은 이제 C++ 0x STL의 일부입니다.

0

그래, STL 포트는 Microsoft (VS 2008)와 GNU 구현 (sta circa gcc 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; 
}