C++ 替换默认STL分配器

C++ 替换默认STL分配器,c++,stl,C++,Stl,我有一个大型(>250个文件)库的源代码,该库大量使用STL容器和字符串。我需要在具有有限堆的嵌入式环境中运行它,因此我希望确保该库本身的堆使用受到限制 显而易见的解决方案是创建一个分配器,但是修改整个代码库以包含分配器模板参数是最后的一个大任务,如果我想要获取源代码的新版本,这是不可取的。全局替换new和delete是不可行的,因为这会影响整个图像,而不仅仅是此库 我的下一个想法是一个愚蠢的C宏技巧,但这似乎是不可能的,尽管我承认自己不是一个聪明的宏作者 所以我想“是否有编译器或pragma开

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

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

我的下一个想法是一个愚蠢的C宏技巧,但这似乎是不可能的,尽管我承认自己不是一个聪明的宏作者

所以我想“是否有编译器或pragma开关在编译时指定分配器类”?但我什么都愿意

我要问的下一个问题是,如果有人能想出一个解决方案,那就是如何在组成这个库的一组文件中对new/delete执行同样的操作

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

所以我想“有没有编译器或pragma开关来指定 编译时的分配器类“?但我什么都愿意

不,没有

看一看

分配器是每个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;
    }
}
在这里,您可以调用您的新建并删除堆上的工作


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

您可以从使用EASTL(Enterprise Arts STL(部分)实现)中获益

这是为嵌入式/游戏开发而设计的,在这样的环境中

EASTL的分配器模型受著名出版物()中的思想启发(或类似?)

EASTL非常适合自定义分配器事实上,它不附带分配器,因此需要提供一个(最小的)分配器才能让应用程序链接


下面是针对EASTL的github repo:

我求助于预处理器以获得可能的解决方案,尽管它目前依赖于GCC 3.4.4实现

GCC
实现包括文件
,该文件又包括另一个文件
,该文件定义了一个宏,该宏定义了实现默认分配器基类的类

由于是在平台相关路径中找到的(
/lib/gcc/i686 pc cygwin/3.4.4/include/c++/i686 pc cygwin/bits
),用我自己的“平台相关”实现取代它,我并不觉得(非常)脏

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


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

gcc 3.4.4已经足够旧了,可以贴上“完全损坏”的标签。为什么不切换到新版本?我认为在GCC中,这只是interna中的一个简单宏,您应该能够切换。默认设置为“新分配器”,但GCC提供了几种替代方案,如“malloc分配器”和池分配器等。假设您可以创建一个有限堆,然后仅为该库重载
operator new
,因此库中的所有
operator new
调用都进入您的有限堆。当有限堆已满并且调用重载的
运算符new
时,您希望采取什么行为?在这种情况下,您真的希望新的
操作员
失败吗?我不相信您会这样做,除非当
operator new
出现故障时,该库仍然可以运行。如果库是数据库缓存,或者类似的东西。这个库是做什么的?我们的做法是创建一个模板类来包装我们使用的每个容器。请看我发布的一个问题:。它为你省去了一些麻烦,也使你更难犯错误。我对我们的解决方案并不完全满意,所以如果有人用更好的解决方案回答你的问题,我可能会考虑修改我们的解决方案。@ SeHe,3.4.4的原因是我们的目标系统是运行VxWorks的卫星硬件,并且该工具链仍然在3.4.4。我不知道“为什么”,只知道要求。所以你是说没有办法告诉STL全局使用自定义分配器;必须确保在使用stl类型时,使用自定义分配器定义它。“是吗?”奥伦斯说。对于特定的编译器,可能有一个选择,但我是根据我的经验单独谈论的。我和OP在同一个地方,不得不这么做。编辑更正的答案。@FailedDev,我在这里发布之前看到了那个页面,对此充满希望。如果我能想出如何使我的任意分配器成为一个“扩展”分配器,那我就太棒了。我也不知道该怎么做。如果你知道,我会给我的下一个狗命名“FieldDeV”……这个话题和C++ 17有什么变化吗?现在是否有一种通用的方法来替换全局分配器?这是一种可能的解决方案,尽管由于std和EASTL名称空间的关系,我不得不编辑EASTL或我的库。我如何在Visual Studio中这样做?我试图找到默认的分配器头文件,但丢失了:)谢谢!
/**
* 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);