Подтвердить что ты не робот

Заменить распределитель STL по умолчанию

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

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

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

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

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

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

4b9b3361

Ответ 1

Я прибег к препроцессору, чтобы получить возможное решение, хотя он в настоящее время полагается на реализацию 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/ в корне моего источника include path, а затем создаю файл c++allocator.h в этой папке. Я определяю требуемый макрос как имя моего класса распределителя, и он работает как шарм, поскольку gcc ищет мои включенные пути перед поиском системы.

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

Ответ 2

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

EASTL - Стандартная библиотека шаблонов Electronic Arts

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

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

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

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

Ответ 3

Итак, я подумал: "Есть ли компилятор или прагма-переключатель, чтобы указать 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);

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

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