Непрерывное выделение памяти для нескольких небольших std::vectors?

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

Есть ли способ использовать allocators, например, для создания смежных std::vectors? Я бы не хотел изобретать велосипед только потому, что мне нужна эта память-локальность в остальном нормальная std::vectors

Я не знаю, как даже начать программировать. Мне нужно создать распределитель, который берет указатель на память, размещает там вектор, а затем каким-то образом передает обратно адрес конца этого вектора, чтобы следующий распределитель std::vector мог захватить его и сделать это снова. Как allocator может вернуть значение?


person sunny    schedule 30.07.2015    source источник
comment
Да, для этого можно использовать распределители. Что вы пробовали? Покажи свою работу :)   -  person Andrew    schedule 30.07.2015
comment
@ Андрей, я кое-что добавил в свой вопрос, но не знаю, с чего начать. Я не работал с распределителями, и до сих пор все, что я сделал, это прочитал разделы Джосуттиса в его справочнике по STL.   -  person sunny    schedule 30.07.2015
comment
Случайно ли размеры известны во время компиляции?   -  person Sergey Kalinichenko    schedule 30.07.2015
comment
@dasblinkenlight да, тип и размер вектора известны. Я знаю все об этих векторах. Теперь мне нужно выяснить, как написать и использовать распределитель, который мог бы возвращать адрес памяти.   -  person sunny    schedule 30.07.2015
comment
@sunny Если размеры остаются прежними и известны во время компиляции, как вы думаете, можно ли вместо этого использовать std::array<T,N>? Гораздо проще разместить их в памяти, и, поскольку вы не увеличиваете свои векторы, ненужные функции-члены, такие как push_back(...), исчезнут. Конечно, если вы используете пред-С++ 11, это не вариант.   -  person Sergey Kalinichenko    schedule 30.07.2015
comment
@dasblinkenlight Существует множество (и некоторые мне неизвестные) зависимостей от реализации std::vector для этих объектов, так что это не вариант. Я на С++ 11   -  person sunny    schedule 30.07.2015
comment
Взгляните на stackoverflow.com/a/18518258/2249683.   -  person    schedule 30.07.2015
comment
@sunny: это случайно не зависимости от обычного std::vector<T, std::allocator<T>> ? Потому что использование пользовательского распределителя влияет на тип вектора.   -  person MSalters    schedule 31.07.2015
comment
@MSalters Насколько я понимаю, в настоящее время компилятор игнорирует тип распределителя для целей определения типа шаблона (где-то видел это в этой презентации: youtube.com/watch?v=YkiYOP3d64E)...но даже если бы это был не тот случай, я согласен с этим...если бы я мог найти решение. То, на что указал Крис Дрю, кажется наиболее вероятным, за исключением того, что я хочу выделить непрерывную память в куче.   -  person sunny    schedule 31.07.2015
comment
Компилятор не может игнорировать это (это библиотека не знает). Однако библиотека обеспечивает преобразования. Но у вас не может быть конверсий по аргументу std::vector<int>&.   -  person MSalters    schedule 31.07.2015
comment
@MSalters Я понимаю вашу точку зрения, но не вижу в этом проблемы?   -  person sunny    schedule 31.07.2015


Ответы (2)


Решением является short_alloc от @HowardHinnant. Я хочу выделить в куче, поэтому должен использовать new, ***, но в остальном опубликованный код Говарда делает именно то, что я хочу.

template <std::size_t N>
class arena
{...
char* buf_ = new char[N] 
// still need to align this but not sure of the syntax 
// to do that with a new statement
...

С моей точки зрения, недостающая часть, когда я задавал вопрос, заключалась в том, что allocators может иметь constructors, которые принимают аргументы:

constexpr int N = 1000*sizeof(int);
arena<N> myArena;
std::vector<int, short_alloc<int, N>> x(MyArena);

Я нашел ссылку на код в другом сообщении SO: Вопросы о распределителе стека Hinnant, на который ссылались из сообщения CodeReview Крис Дрю предложил в своем комментарии выше. Спасибо вам всем.

***Код действительно использует new в методе allocate, поэтому я не уверен, выделяется ли он в стеке (как видно из объявления buf_*) или в куче (использование new)...

person sunny    schedule 31.07.2015

По вашему требованию я бы реализовал собственный распределитель, который расширяет std::allocator и переопределяет метод выделения, освобождения, который захватывает фрагменты из пула памяти. Если вы уже знаете максимальный требуемый размер, выбор размера пула памяти не должен быть проблемой.

person kchoi    schedule 31.07.2015
comment
Да, я согласен, это стратегия, которую я изложил в своем первоначальном вопросе, но мне было непонятно, как ее выполнить с помощью распределителя. Решение, которое я разместил ниже, делает то, что я хотел. - person sunny; 31.07.2015
comment
Если вы хотите выделить в стеке, взгляните на захват памяти с помощью встроенной alloca. У вашего пользовательского распределителя есть выбор, откуда взять пул памяти. Надеюсь, поможет. Поскольку это размещается в стеке, оно будет автоматически отброшено при возврате. - person kchoi; 31.07.2015