An STL implementation that uses a dynamic / state allocator?

Does anyone know of an STL implementation that allows dynamic porting of dynamic allocators to a container instance before dynamically migrating?

The scenario is that we have a shared memory allocator that manages multiple memory pools, and for each instance of say stl :: vector we want to allocate each instance from a different memory pool.

The problem with standard STL implementations is that you can only define a memory pool for a type, i.e. the entire vector of type int will be allocated from one pool.

I already changed our standard stl :: allocator by default for someone who has state, i.e. the pool from which we want to allocate this instance, but this does not work well for say stl :: list, where it allocates things in default ctor.

For reasons related to our library, we also do not have a valid ctor pool for all objects, so we want to call the "set memory pool" function before users can use the stl container.

Does anyone come across an implementation that supports such things?

+6
c ++ stl allocator
source share
5 answers

I'm definitely not sure about your question. Therefore, I will talk about the case of a full distributor.

In C ++ 03, any allocator should be able to free resources allocated by another allocator of the same type.

The C ++ 0x standard effectively removes this restriction and allows full dispensers to be transferred to STL containers if they are Allocator Aware containers (I think it covers all containers packaged in STL as they model the sequence).

For example: [allocator.adaptor] $20.10 Class scoped_allocator now part of C ++ 0x STL.

+4
source share

The dialed dispenser may use a common dispenser below it to make distributions.

Allocator must support the following functions:

  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 ); 

Assuming you have a mechanism that just allocates memory and frees memory, you can use this to implement some of the above functions.

The advantage of dispensers issued is that you know that you are going to create many objects of the same size and, therefore, you can create your own โ€œpagesโ€ to fit each other. The biggest problem may be that you have to allocate () return adjacent buffers (and, indeed, they need a vector).

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

Your question still remains unclear why this is not enough. You can initialize a memory pool with once logic. (If it's multithreading, you can use boost :: once to achieve this).

+2
source share

The problem with the standard STL is that you can only define a memory pool based on type i.e. an entire vector of type int would be allocated from a single pool.

This is not entirely true. You can have different vectors containing int elements, each of which has a different type of dispenser.

However, regarding the question -

Does anyone know of an STL implementation that allows dynamically allocated allocators to be passed to a container instance before use.

- it is simply not supported by the standard C ++ library (STL), therefore, perhaps, there are implementations in which distributors for each object work, this is not portable.

For a detailed analysis of why and how to use custom allocators, see Scott Meyers book Effective STL , in particular clause 11: Understand the legitimate use of custom allocators.

+1
source share

One option is to use a local thread variable to hold the pointer on the memory pool to use and commit it to the allocator implementation. For example (using 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 

The API that myallocator should implement is described here .

Unfortunately, due to limitations in the STL API, this is as good as you can get without overriding the STL. However, there may be third-party libraries that allow you to pass to the distributor to the object constructor somewhere.

0
source share

Well, thatโ€™s why the STL port seems to support such functionality where, like Microsoft (VS 2008) and the GNU implementation (stl circa gcc 3.4.1 port), itโ€™s not the way they allocate / release things in ctors / dtors.

Here is my test code showing how to do this. Warning that this is not a complete implementation in any way!

 #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; } 
0
source share

All Articles