У меня есть функция, которая получает входной буфер n
байты и потребности вспомогательный буфер n
байты для обработки данного входного буфера.
(Я знаю, что вектор выделяет память во времени выполнения, скажем, что я использую вектор, который использует статическую предварительно выделенную память. Предположите, что это не вектор STL.)
Обычный подход
void processData(vector<T> &vec) {
vector<T> &aux = new vector<T>(vec.size()); //dynamically allocate memory
// process data
}
//usage:
processData(v)
Так как я работаю в среде реального времени, я хочу предварительно выделить всю память, в которой я буду когда-либо нуждаться заранее.
Буфер выделяется только однажды при запуске. Я хочу это каждый раз, когда я выделяю вектор, я автоматически выделю вспомогательный буфер для моего processData
функция.
Я могу сделать что-то похожее с шаблонной функцией
static void _processData(vector<T> &vec,vector<T> &aux) {
// process data
}
template<size_t sz>
void processData(vector<T> &vec) {
static aux_buffer[sz];
vector aux(vec.size(),aux_buffer); // use aux_buffer for the vector
_processData(vec,aux);
}
// usage:
processData<V_MAX_SIZE>(v);
Однако работание много с шаблонами не является большой забавой (теперь, давайте перекомпилируем все, так как я изменил комментарий!), и это вынуждает меня сделать некоторую бухгалтерию каждый раз, когда я использую эту функцию.
Есть ли какие-либо более хорошие проекты вокруг этой проблемы?
Я не понимаю, как вы можете получить именно то, что описываете. Что-то вроде этого могло бы стать для вас хорошим компромиссом.
void processData(vector<T>& vec)
{
static vector<T> aux(vec.size());
if (vec.size() > aux.size()) {
aux.resize(vec.size());
}
...
}
Я думаю, вы могли бы предварительно -allocate и mlock () достаточно большой пул памяти при запуске, а затем использовать обычные контейнеры STL с распределителями пула памяти ( Boost из FSBA или ваши собственные).
Я изучал это для нашего программного обеспечения реального времени, но тесты показали, что распределение памяти на нашем оборудовании достаточно быстрое для наших целей.
Возможно, вы можете переопределить операторы new и delete, но тогда вам придется управлять всей своей памятью самостоятельно. В начале вы можете выделить столько памяти, сколько хотите:
void* operator new (std::size_t size) throw (std::bad_alloc);
void* operator new[] (std::size_t size) throw (std::bad_alloc);
void operator delete (void* ptr) throw ();
void operator delete[] (void* ptr) throw ();
vector aux(vec.size(),aux_buffer); // используем aux_buffer для вектора
Это новое в STL? Или пользовательское расширение?
Типичным решением было бы использование пользовательского аллокатора. Однако это не обязательно "красивее" в коде.
Некоторые вводные слайды (предупреждение: powerpoint!)
Wikipedia
Google
допустим, я использую вектор. который использует статическую предварительно выделенную память
Тогда вы должны быть в состоянии получить размер (или максимальный размер) предварительно выделенной памяти во время компиляции. Если бы такой вектор имел свой размер как аргумент шаблона, то работа с функцией processData была бы проще.
template<class T, size_t sz>
class vector
{
enum { size = sz } //either max size
...
}
template<class Vector>
static void _processData(Vector &vec,Vector &aux)
{
// process data
}
template<class Vector>
void processData(Vector &vec) {
static aux_buffer[Vector::size];
//no need to pass size into constructor, as Vector type knows it already
Vector aux(aux_buffer); // use aux_buffer for the vector
_processData(vec,aux);
}
// usage:
vector<int, 30> v1;
vector<float, 40> v2;
//no need to specify template parameter explicitly
//every call uses its own function instance and its own buffer of different size
processData(v1);
processData(v2);
Не могли бы вы создать небольшую структуру, содержащую ваш вектор и буфер такого же размера? Тогда ваш вектор будет нести свой буфер обработки вместе с собой, куда бы он ни направлялся. Если вы передадите его по ссылке или указателю, вам следует избежать накладных расходов на копирование. Псевдокод следует ниже:
struct Container
{
vector<T> vec;
vector<T> buf;
Container(int size)
{
vec.reserve(size);
buf.reserve(size);
}
};
Любая функция, которая в настоящее время принимает ваш аргумент вектора, затем примет Контейнер
.
Даже если вам это удастся, это может не достичь того, чего вы хотите. В зависимости от того, какую ОС вы используете и как она реализует виртуальную память, вы можете обнаружить, что вы получаете ленивое выделение
, при котором только часть вашего распределения памяти фактически выделяется и отображается изначально, а дальнейшие страницы отображаются позже. в результате ошибок страниц. Если в вашей ОС есть mlock
или аналогичный, вы можете обойти это.
Вам нужно беспокоиться не о векторе
, а о распределителе памяти.
Вы могли бы идеально создать распределитель памяти, который предварительно выделяет ее память, а затем передает ее вектору при его построении, для этого и нужен параметр шаблона Alloc
!
И чтобы убедиться, что память не выделена «виртуально», прикоснитесь к ней при выделении.
scoped_array<byte> buffer = new byte[SIZE];
memset(buffer.get(), 0, SIZE);
Теперь вам «просто» нужно реализовать собственный распределитель, который ссылается на этот пул памяти и передать его векторной реализации :)