是否有人知道STL实现允许在使用之前将动态分配器传递给容器的实例。
场景是我们有一个通用的内存分配器来管理大量的内存池,对于我们想要从不同的内存池分配每个实例的stl :: vector的每个实例。
标准STL实现的问题在于,您只能在类型基础上定义内存池,即int类型的所有向量都将从同一个池中分配。
我已经将我们的默认stl :: allocator换成了一个状态,即我们想要分配这个实例的池,但这对于stl :: list来说效果不好,它在那里分配东西默认ctor。
由于与我们的库相关的原因,我们在ctor中没有所有对象的有效池,因此我们想在用户使用stl容器之前调用'set memory pool'函数。
有没有人遇到过支持此类事情的实现?
答案 0 :(得分:4)
我对你的问题不太确定。所以我将介绍状态完全分配器的情况。
在C ++ 03中,任何分配器都应该能够释放由同一类型的另一个分配器分配的资源。
C ++ 0x标准实际上删除了这个限制并允许将状态完全分配器传递给STL容器,只要它们是 Allocator Aware 容器(我认为它涵盖了随包装的所有容器) STL,因为他们模拟序列)。
例如:[allocator.adaptor] $20.10 Class scoped_allocator
现在是C ++ 0x STL的一部分。
答案 1 :(得分: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()强制返回连续的缓冲区(实际上vector需要它们)。
http://www.cplusplus.com/reference/std/memory/allocator/
你的问题仍然有点不清楚为什么这还不够。您可以使用“一次”逻辑初始化内存池。 (如果它是多线程的,你可以使用boost :: once来实现这一点)。
答案 2 :(得分:1)
标准STL的问题 实现是你只能 基于类型定义内存池 即int类型的所有向量 从同一个池分配。
这不完全正确。您可以使用不同的向量来保存int
元素,每个元素具有不同的分配器类型。
然而,关于这个问题 -
有人知道STL吗? 允许动态的实现 要传递给的分配器 使用前容器的实例。
- C ++标准库(STL)根本不支持它,因此,虽然可能存在每个对象分配器工作的实现,但它不可移植。
有关使用自定义分配器的原因和方法的详细分析,请参阅Scott Meyers's book Effective STL,特别是第11项:了解自定义分配器的合法使用。
答案 3 :(得分: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必须实现的API描述为here。
不幸的是,由于STL API的限制,这可以在没有重新实现STL的情况下获得。但是,可能有第三方库允许您将分配器传递给对象的构造函数。
答案 4 :(得分:0)
好吧所以STL端口似乎确实支持这种功能,其中Microsoft(VS 2008)和GNU实现(stl大约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;
}