2015-03-11 2 views
2

У нас есть библиотека, которая предоставляет интерфейс C через extern "C" и используется из кода C, но внутри нее используются контейнеры STL и некоторые функции C++, такие как RAII для удобства.Возможно ли написать специализированный распределитель STL, который использует указатели на функции распределения, предоставляемые пользователем?

Теперь есть новое требование, чтобы библиотека могла принимать указатели на пользовательскую функцию malloc и free, исходящую из кода клиента, и использовать ее для размещения внутри. Я могу разместить их в контекстной структуре библиотеки и использовать их там, где это необходимо, но использование их с помощью STL вызывает недоумение ...

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

Возможно ли это работать предпочтительно безопасным потоком (без использования глобалов)?

ответ

5

Я смотрел на классах Allocator но кажется STL контейнеры должны быть в состоянии использовать конструкторы по умолчанию для создания распределителя

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

extern "C" 
{ 
    typedef void* (*allocation_function)(size_t); 
    typedef void (*deallocation_function)(void*); 
} 

template<typename T> 
class Allocator 
{ 
public: 
    typedef T value_type; 

    Allocator(allocation_function alloc, deallocation_function dealloc) 
    : m_allocate(alloc), m_deallocate(dealloc) 
    { } 

    template<typename U> 
    Allocator(const Allocator<U>& a) 
    : m_allocate(a.m_allocate), m_deallocate(a.m_deallocate) 
    { } 

    T* allocate(size_t n) 
    { return static_cast<T*>(m_allocate(n * sizeof(T))); } 

    void deallocate(T* p, size_t) 
    { m_deallocate(p); } 

private: 
    template<typename U> 
    friend class Allocator<U>; 

    template<typename U> 
    friend bool operator==(const Allocator<U>&, const Allocator<U>&); 

    allocation_function m_allocate; 
    deallocation_function m_deallocate; 
}; 

template<typename T> 
bool operator==(const Allocator<T>& l, const Allocator<T>& r) 
{ return l.m_allocate == r.m_allocate; } 

template<typename T> 
bool operator!=(const Allocator<T>& l, const Allocator<T>& r) 
{ return !(l == r); } 


Allocator<int> a(custom_malloc, custom_free); 
std::vector<int, Allocator<int>> v(a); 

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

+0

Этот конструктор std :: map вызывает у меня проблемы: 'map(): Mybase (key_compare(), allocator_type())' поэтому вопрос. (В VS2008). Но это может быть хорошо, потому что есть экземпляры, построенные конструктором по умолчанию. Являются ли компиляторы достаточно умными, чтобы не жаловаться, если я вообще не использую конструктор по умолчанию при объявлении переменных? – Calmarius

+1

Да. Если вы не используете конструктор по умолчанию (и явно не создаете экземпляр всего типа 'map'), тогда конструктор по умолчанию для распределителя не нужен. –

+0

Я не знаю, какая часть требований к распределителю C++ 11 VS2008 реализуется, вам может потребоваться предоставить ряд других функций-членов, таких как 'construct' и' destroy', и определить несколько typedefs, таких как 'rebind :: other', 'pointer',' const_pointer', 'reference' и т. д., но если вы все сделаете, то он должен работать нормально. –

-2

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

+1

_ «Поскольку распределители не могут быть заполнены по-умолчанию, но должны быть по умолчанию конструктивными», ни одна из этих вещей не является истинной в наши дни. –

+0

@JonathanWakely Я говорю о C++ - 03 – randomusername

+2

Они не обязательно должны быть конструктивными по умолчанию даже в C++ 03. И это неправда, что они не могут быть сдержанными, это просто не гарантирует, что ваша реализация будет поддерживать его ...но на практике все поддерживают генераторы с сохранением состояния. Во всяком случае, использование шаблонов не решает проблему использования предоставляемых пользователем функций распределения (если только они не ссылаются только на глобальные переменные, исключенные из ОП) –

Смежные вопросы