替换默认的STL分配器

时间:2011-11-23 18:53:27

标签: c++ stl

我有一个大型(> 250个文件)库的源代码,它大量使用STL容器和字符串。我需要在具有有限堆的嵌入式环境中运行它,所以我想确保这个库本身在其堆使用方面受到限制。

显而易见的解决方案是创建一个分配器,但是修改整个代码库以包含allocator模板参数是最后的一项重要工作,如果我想要使用新版本的源,这是不可取的。全局替换new和delete是不可行的,因为这会影响整个图像,而不仅仅是这个库。

我的下一个想法是一个愚蠢的C宏技巧,但这似乎不太可能,虽然我承认不是一个聪明的宏作者。

所以我认为“在编译时是否有编译器或编译指示开关来指定分配器<>类”?但我对任何事都持开放态度。

我要问的下一个问题是,如果有人能提出解决方案,那么如何在包含该库的文件集中对新/删除做同样的事情。

我正在使用gcc 3.4.4工具链在Cygwin下运行它,目标是VxWorks,如果这引发了任何想法。

3 个答案:

答案 0 :(得分:7)

我使用预处理器来获得可能的解决方案,尽管它目前依赖于GCC 3.4.4实现。

GCC <memory>实现包含文件<bits/allocator.h>,后者又包含另一个文件<bits/c++allocator.h>,该文件定义了一个定义实现默认分配器基类的类的宏。

由于在依赖于平台的路径/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/i686-pc-cygwin/bits中找到,因此我不会感到(非常)肮脏地用我自己的“平台相关”实现来取代它。 / p>

所以我只在源代码的包含路径的根目录中创建一个文件夹bits/,然后在该文件夹中创建文件c++allocator.h。我将所需的宏定义为我的分配器类的名称,它就像一个魅力,因为gcc在搜索系统包括之前搜索我的包含路径。

感谢您的所有回复。我想我可以使用这个“解决方案”,只有在我使用3.4.4时它才会起作用。

答案 1 :(得分:6)

您可以从使用EASTL(Enterprise Arts STL(部分)实施)

中受益

EASTL -- Electronic Arts Standard Template Library

这适用于global heap is really scarce, non-existent or problematic in general的环境中的嵌入式/游戏开发。

EASTL的分配器模型的灵感来自(或类似于?)着名的Towards a Better Allocator Model出版物(PDF)中的想法。

EASTL非常适合自定义分配器。 实际上,它没有附带分配器 ,因此提供(最小的)必需甚至可以让应用程序链接。

以下是EASTL的github回购:https://github.com/paulhodge/EASTL

答案 2 :(得分:3)

  

所以我认为“是否有编译器或编译指示开关来指定   分配器&LT;&GT;在编译时上课“?但我对任何事情都持开放态度。

没有。

看看here

分配器是每个stl容器中的模板参数。你需要改变它们。在使用嵌入式系统时,我在过去做过同样的事情。如果你愿意,我可以给你一些指示:

基本模板分配器:

namespace PFM_MEM {
    template <class T>
    class CTestInstAllocator {
    public:
        // type definitions
        typedef size_t    size_type;
        typedef ptrdiff_t difference_type;
        typedef T*        pointer;
        typedef const T*  const_pointer;
        typedef T&        reference;
        typedef const T&  const_reference;
        typedef T         value_type;

        // rebind CTestInstAllocator to type U
        template <class U>
        struct rebind {
            typedef CTestInstAllocator<U> other;
        };

        // return address of values
        pointer address (reference value) const {
            return &value;
        }
        const_pointer address (const_reference value) const {
            return &value;
        }

        /* constructors and destructor
        * - nothing to do because the CTestInstAllocator has no state
        */
        CTestInstAllocator() {
        }
        CTestInstAllocator(const CTestInstAllocator&) {
        }
        template <class U>
        CTestInstAllocator (const CTestInstAllocator<U>&) {
        }
        ~CTestInstAllocator() {
        }

        // return maximum number of elements that can be allocated
        size_type max_size () const {
            return std::numeric_limits<size_t>::max() / sizeof(T);
        }

        // pvAllocate but don't initialize num elements of type T by using our own memory manager
        pointer allocate (size_type num) {
            /**
            * pvAllocate memory custom memory allocation scheme
            */
            return(pointer)(CPfmTestInstMemManager::pvAllocate(num*sizeof(T)));
        }
        // initialize elements of allocated storage p with value value
        void construct (pointer p, const T& value) {
            // initialize memory with placement new
            new((void*)p)T(value);
        }

        // destroy elements of initialized storage p
        void destroy (pointer p) {
            // destroy objects by calling their destructor
            p->~T();
        }
        // vDeallocate storage p of deleted elements
        void deallocate (pointer p, size_type num) {
            /**
            *Deallocate memory with custom memory deallocation scheme
            */
            CPfmTestInstMemManager::vDeallocate((void*)p);
        }
    };

    // return that all specializations of this CTestInstAllocator are interchangeable
    template <class T1, class T2>
    bool operator== (const CTestInstAllocator<T1>&,
        const CTestInstAllocator<T2>&) {
            return true;
    }
    template <class T1, class T2>
    bool operator!= (const CTestInstAllocator<T1>&,
        const CTestInstAllocator<T2>&) {
            return false;
    }
}

请注意以下几点:

/**
* pvAllocate memory custom memory allocation scheme
*/
return(pointer)(CPfmTestInstMemManager::pvAllocate(num*sizeof(T)));

// vDeallocate storage p of deleted elements
void deallocate (pointer p, size_type num) {
/**
*Deallocate memory with custom memory deallocation scheme
*/
CPfmTestInstMemManager::vDeallocate((void*)p);

在这里您可以调用您的 new并删除堆上的哪些工作。

我可以为您提供一个如何构建一些基本内存管理器的示例,以帮助您进一步。