#c #c 17 #allocator
#c #c 17 #распределитель
Вопрос:
Допустим, я пишу библиотеку и хочу разрешить пользователю предоставлять свой собственный экземпляр распределителя, чтобы он мог упаковывать память так, как ему хотелось бы. Каковы некоторые способы достижения этого конкретно в C 17?
Например, если я использую что-то вроде new int[5] , это не будет использовать пользовательский распределитель пользователей. Что эквивалентно этому утверждению при разрешении пользовательского распределителя?
Комментарии:
1. Используйте контейнеры из стандартной библиотеки. Все они указаны таким образом, что включает экземпляр типа распределителя, который объект контейнера использует для выделения и освобождения необходимой ему памяти. Ничто не мешает пользователю определять свои собственные типы распределителей, если они соответствуют требованиям, которые стандарт определяет для распределителей.
2. Я думаю, что я пытаюсь сказать, что, допустим, моя библиотека использует указанный распределитель, теперь, как мне убедиться, что он используется везде? Должен ли я явно вводить std::vector<int, userAllocator<int>> ?
3. @rrohak «моя библиотека использует указанный распределитель» не уверен, что это значит, ваше объявление вектора с пользовательским распределителем выглядит нормально.
4. В качестве предостережения: библиотеки управления памятью C очень эффективны и были оптимизированы в течение двух десятилетий, чтобы быть хорошими (в общем случае). Вам было бы трудно добиться большего. но если предположить, что вы можете показать, что оно того стоит, тогда это можно сделать. Но это нетривиально для правильного понимания и должно быть оставлено в качестве проекта экспертного уровня.
Ответ №1:
Любая свободная функция, которая будет выделять, должна стать шаблоном функции.
void foo(int arg); // has new int[N] somewhere
становится
template <typename Allocator = std::allocator<int>>
void foo(int arg, Allocator alloc = {}); // has alloc.allocate(N) somewhere
Любой класс, функции-члены которого выделяют, должен стать шаблоном класса.
class bar {
public:
bar() = default;
void baz() // has new double[N] somewhere
};
становится
template <typename Allocator = std::allocator<double>>
class bar {
public:
bar(Allocator alloc = {}) : alloc(alloc) {}
void baz() // has alloc.allocate(N) somewhere
private:
Allocator alloc;
};
Если вам нужно выделить значения нескольких типов, решите, какое из них наиболее естественно требовать, и используйте typename std::allocator_traits<Allocator>::template rebind_alloc<OtherType>
для получения типа распределителя OtherType
.
Все, что использует любую из этих функций или классов, должно принимать распределитель для передачи ему.
Скорее всего, вы будете использовать стандартные типы библиотек. Вы должны разрешить вызывающей стороне также указывать распределитель там.
namespace rrohak_lib {
class SomeValue { /*...*/ };
template <typename Allocator = std::allocator<SomeValue>>
void frobnicate(std::vector<SomeValue, Allocator> amp; vec);
}