C++ 如何显式管理异构类型(和大小)的多个池分配器?

C++ 如何显式管理异构类型(和大小)的多个池分配器?,c++,memory-management,boost,c++11,C++,Memory Management,Boost,C++11,场景:我有一个G类,它(通常)由数千个从N类派生的对象组成。所有这些对象都有一个定义良好的生命周期。首先,构造一个对象G,然后添加N个派生对象,然后使用G进行一些计算,这不会改变N个派生对象,然后G超出范围,并且使用它,组成N个派生对象。N派生对象依次包含指向添加到同一G对象的其他N派生对象的指针或标准容器。G表示具有异构节点的图 我的目标是: 最小化分配每个N派生对象的成本 最大化属于同一个G对象的N个派生对象的引用位置 通过为所有N个派生对象取消分配单个块,将取消分配的成本降至最低 为了能够

场景:我有一个G类,它(通常)由数千个从N类派生的对象组成。所有这些对象都有一个定义良好的生命周期。首先,构造一个对象G,然后添加N个派生对象,然后使用G进行一些计算,这不会改变N个派生对象,然后G超出范围,并且使用它,组成N个派生对象。N派生对象依次包含指向添加到同一G对象的其他N派生对象的指针或标准容器。G表示具有异构节点的图

我的目标是:

  • 最小化分配每个N派生对象的成本
  • 最大化属于同一个G对象的N个派生对象的引用位置
  • 通过为所有N个派生对象取消分配单个块,将取消分配的成本降至最低
  • 为了能够定义多个具有独立生命周期的独立G对象,可能需要在并发线程中管理这些独立G对象,而无需线程同步
  • 对我来说,这似乎需要多个池分配器-它们像使用堆栈一样进行分配。。。并且仅当池被销毁时才释放池分配

    我研究了boostpool分配器,但没有找到为不同大小的异构对象建立多个独立池的方法

    接下来,我定义了自己的自定义分配器-但很快发现,虽然我可以将其作为模板参数传递给标准容器,如std::vector、std::set、std::list等-允许我指定池分配器的类型。。。我之所以没有做到这一点,是因为我无法轻松地指定两个原本独立的容器应该共享同一个(非全局)分配器池。我认识到一个解决方案是使用静态/全局线程,并限制自己在一个线程中只构建G对象。我还考虑使用线程本地存储将自定义分配器与相关池关联。。。但我认为这很难看。这两种方法都不直接支持在同一线程中交错构造两个独立的G对象

    我是否忽略了Boost中问题的现有解决方案

    有没有比使用静态/全局或线程本地存储更好的习惯用法来实现我的目标

    更新

    我已经阅读了Stroustrup的faq和boost::container文档。起初,Boost::container让我深受鼓舞,但对于没有看到如何在这些容器中使用有状态分配器的具体示例,我感到失望。我已经能够简化我原来的问题来问。。。给定一个结构:

    struct DataUnit { map<int,string> m; list<int> l; }
    
    结构数据单元{map m;list l;} 我如何确保,对于DataUnit的每个实例,都有一个单独的池,从中分配m和l的内部成分?如果我将一个自定义分配器传递给map和list,m和l将获得该容器的独立实例。我最初认为我可以使用get_allocator()用我的aerena/pool初始化分配器。。。但是,遗憾的是,在vector的默认构造函数返回之前调用了allocate()。。所以我不能这么做

    更奇怪的是,我发现,在涉足boost::container一段时间后。。。vanilla std容器有一个get_分配器()(在MSVC 2010和2012以及g++4.6.3上),这表明这些上下文中的标准库具有类似于boost::container的有状态分配器支持

    不幸的是,对于我最初的问题,我仍然没有可行的解决方案(尽管我现在可以更雄辩地表达出来)

    更新2


    谢谢你,pmr,如果你把你最后的评论归类为答案,我会给你一个“正确答案”。)在找到boost::container之后,我的问题是,我希望它的文档能够明确说明任何新功能,比如在构造时传递分配器对象。。。我没有正确检查boost::container源代码。我现在确信,容器为我上面提到的所有问题提供了一个非常优雅和直观的解决方案(如果文档不完整的话)。再次感谢

    警告:完全未测试的代码。我不知道它是哪种“惯用语”——但下面1.5页的代码应该可以解决您的问题

    class GraphNodeAllocator
    {
        struct CMemChunk
        {
            CMemChunk* pNext;
            BYTE* data()
            {
                return static_cast<BYTE*>( static_cast<void*>( this + 1 ) );
            }
        };
    
        CMemChunk* m_pChunk; // Most recently allocated a.k.a. current chunk
        BYTE* m_pFirstByte;  // First free data byte within the current chunk
        size_t m_freeBytes;  // Count of free bytes within the current chunk
    
        static const size_t cbChunkAlloc = 0x10000; // 65536 bytes per single allocation
        static const size_t cbChunkPayload = cbChunkAlloc - sizeof( CMemChunk );
    
        void* Allocate( size_t sz )
        {
            if( sz > cbChunkPayload )
                return NULL;
    
            if( m_freeBytes >= sz )
            {
                // Current chunk has the space
                m_freeBytes -= sz;
                void* res = m_pFirstByte;
                m_pFirstByte += sz;
                return res;
            }
    
            // Need a new chunk
            CMemChunk* pChunk = static_cast< CMemChunk* >( malloc( cbChunkAlloc ) );
            if( NULL == pChunk )
                return NULL;
            pChunk->pNext = m_pChunk;
            m_pChunk = pChunk;
            m_pFirstByte = m_pChunk->data();
            m_freeBytes = cbChunkPayload;
            return Allocate( sz );
        }
    
    public:
        inline GraphNodeAllocator(): m_pChunk( NULL ), m_pFirstByte( NULL ), m_freeBytes( 0 ) { }
    
        inline ~GraphNodeAllocator()
        {
            while( NULL != m_pChunk )
            {
                CMemChunk* pNext;
                pNext = m_pChunk->pNext;
                free( m_pChunk );
                m_pChunk = pNext;
            }
        }
    
        template<typename E>
        inline E* newNode()
        {
            void* ptr = Allocate( sizeof( E ) );
            if( NULL == ptr ) return NULL;
            return ::new( ptr ) E();
        }
    };
    
    类GraphNodeAllocator
    {
    结构CMemChunk
    {
    CMemChunk*pNext;
    字节*数据()
    {
    返回static_cast(static_cast(this+1));
    }
    };
    CMemChunk*m_pChunk;//最近分配的又称当前块
    BYTE*m_pFirstByte;//当前块中的第一个可用数据字节
    size\u t m\u freeBytes;//当前块中的可用字节计数
    静态常量大小\u t cbChunkAlloc=0x10000;//每次分配65536字节
    静态常量大小\u t cbChunkPayload=cbChunkAlloc-sizeof(CMemChunk);
    无效*分配(大小)
    {
    如果(sz>cbChunkPayload)
    返回NULL;
    如果(m_freeBytes>=sz)
    {
    //当前块具有空间
    m_freeBytes-=sz;
    void*res=m_pFirstByte;
    m_pFirstByte+=sz;
    返回res;
    }
    //需要一块新的吗
    CMemChunk*pChunk=static_cast(malloc(cbChunkAlloc));
    if(NULL==pChunk)
    返回NULL;
    pChunk->pNext=m_pChunk;
    m_pChunk=pChunk;
    m_pFirstByte=m_pChunk->data();
    m_freeBytes=cbChunkPayload;
    收益分配(sz);
    }
    公众:
    内联GraphNodeAllocator():m_pChunk(NULL)、m_pFirstByte(NULL)、m_freeBytes(0){}
    内联~GraphNodeAllocator()
    {
    while(NULL!=m_pChunk)
    {
    CMemChunk*pNext;
    pNext=m_pChunk->pNext;
    免费(m_pChunk);
    m_pChunk=pNext;
    }
    }
    模板
    内联E*newNode()