Заменить распределитель STL по умолчанию - PullRequest
20 голосов
/ 23 ноября 2011

У меня есть источник для большой (> 250 файлов) библиотеки, которая интенсивно использует контейнеры и строки STL. Мне нужно запустить его во встроенной среде с ограниченной кучей, поэтому я хочу убедиться, что эта библиотека ограничена в использовании кучи.

Очевидное решение заключается в создании распределителя, но изменение всей базы кода для включения параметра шаблона распределителя является большой задачей последней инстанции и нежелательно в случае, если я когда-нибудь захочу взять новую версию исходного кода. Глобальная замена новых и удаление невозможна, так как это влияет на все изображение, а не только на эту библиотеку.

Моей следующей мыслью был глупый трюк с макросом C, но, похоже, это было бы невозможно, хотя я признаю, что не был умным автором макросов.

Итак, я подумал, "есть ли компилятор или прагма-переключатель для указания класса allocator <> во время компиляции"? Но я открыт для всего.

Следующий вопрос, который я задам, если кто-нибудь может придумать решение, это как сделать то же самое для new / delete в наборе файлов, входящих в эту библиотеку.

Я использую набор инструментов gcc 3.4.4 для запуска этого под Cygwin, с целью VxWorks, если это вызывает какие-либо идеи.

Ответы [ 3 ]

7 голосов
/ 28 ноября 2011

Я прибег к препроцессору, чтобы получить возможное решение, хотя в настоящее время он работает на основе реализации 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) , я не чувствую себя (очень) грязно, вытесняя его своей собственной "зависимой от платформы" реализацией.

Поэтому я просто создаю папку bits/ в корне пути включения моего источника, а затем создаю файл c++allocator.h в этой папке. Я определяю требуемый макрос как имя моего класса-распределителя, и он работает как талисман, поскольку gcc выполняет поиск по моим путям включения перед поиском в системе.

Спасибо за все ваши ответы. Я думаю, что я могу пойти с этим «решением», которое будет работать, только если я использую 3.4.4, вероятно.

6 голосов
/ 25 ноября 2011

Вы могли бы получить выгоду от использования EASTL (Enterprise Arts STL (частичная) реализация)

EASTL - Стандартная библиотека шаблонов электронных искусств

Это было предназначено для встраиваемых /разработка игр, в средах, где глобальная куча действительно недостаточна, вообще отсутствует или проблематична .

Модель распределителя EASTL была вдохновлена ​​(или напоминает ?) Идеями в знаменитой публикации На пути к лучшей модели распределителя ( PDF )).

EASTL хорошо подходит для пользовательских распределителей. На самом деле, он не поставляется с распределителем , поэтому для предоставления (минимального) требуется , чтобы даже получить приложение для ссылки.

Вот репозиторий github для EASTL: https://github.com/paulhodge/EASTL

3 голосов
/ 23 ноября 2011

Так что я подумал "есть ли компилятор или прагма, чтобы указать allocator <> class во время компиляции "? Но я открыт для всего.

Нет, нет.

Взгляните здесь .

Распределители являются аргументом шаблона в каждом контейнере 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);

Вот место, где вы звоните своему новому и удаляете, которые работают в вашей куче.

Я мог бы предоставить вам пример того, как создать некоторый базовый менеджер памяти, чтобы помочь вам в дальнейшем.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...