Какой контейнер C ++ stl мне следует использовать? - PullRequest
0 голосов
/ 25 июня 2018

Представьте себе следующие требования:

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

uint32_t timestamp;
uint16_t place;
struct SomeData someData;
  • имеет метку времени (uint32_t), место (uint16_t) и некоторые данные в структуре

  • имеют постоянное количество наборов данных. Если приходит новый, самый старый выбрасывается.

  • число «мест» является динамическим, пользователь может вставлять новые во время выполнения

  • должна быть возможность перебирать данные до следующего более нового или более старого набора данных, но только если место совпадает

  • нужно вставить только в конце

  • память должна быть выделена один раз при запуске программы

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

  • требования к памяти должны быть низкими

РЕДАКТИРОВАТЬ: - Контейнер должен всю память, которая не используется в противном случае, поэтому он может быть большим.

Я не уверен, какой контейнер мне следует использовать. Это встроенная система, которая не должна использовать boost и т. Д.

Я вижу следующие возможности:

std :: vector - недостатки: вставка в конце требует, чтобы все объекты были скопированы, и в течение этого времени другой поток не может получить доступ к вектору. Редактировать: Этого можно избежать, если использовать его как кольцевой буфер - см. Комментарии ниже. При переборе по вектору я должен проверить идентификатор места. Может также быть проблемой выделение большого объема памяти как одного блока - потому что память может быть сегментирована?

std::deque - по сравнению с std::vector вставка (и pop_back) быстрее, но требуется память? Итераторы не становятся недействительными, если вставка находится в конце. Но я все еще должен повторить и проверить второй идентификатор («место»). Я думаю, что не нужно выделять всю память в одном большом блоке, как в случае с вектором или массивом. Если элемент добавляется впереди, а другой удаляется в конце (или удаляется первым и добавляется после), я полагаю, не происходит выделение памяти?

std::queue - вместо дек, мне лучше использовать очередь? Правда ли, что во многих реализациях очередь добавляется просто как deque?

std::map - Подобно deque любые итераторы для существующих элементов не станут недействительными. Если я сделаю ключ комбинацией места и метки времени, то итерация по карте может быть быстрее, потому что она уже отсортирована? Требования к памяти карты?

std::multimap - так как количество мест не является постоянным, я не могу сделать мультикарту с "местом" в качестве индекса.

std::list - не имеет здесь никакого преимущества перед deque?

Некоторые предлагали использовать кольцевой буфер. Если я не хочу, чтобы память выделялась как один большой блок, мне все равно придется использовать контейнер, и большинство вопросов выше остаются в силе.

Обновление: Я буду использовать кольцевой буфер, как предложено здесь, но с использованием deque в качестве основного контейнера. Чтобы иметь возможность быстро прокручивать наборы данных с предварительно выбранным «местом», я в конечном итоге введу два дополнительных индекса в структуру данных, которые будут указывать на предыдущий и следующий индексы с тем же местом.

Сколько памяти будет использовано? В моем особом случае размер структуры составляет 56 байт. Библиотека GNU использует минимальный размер блока 512 байт, компилятор IAR - 16 байт. Следовательно, используемый размер блока будет 512 или 56 байт соответственно. Помимо двух итераторов (по 4 указателя в каждом) и размера, для каждого блока будет храниться указатель. Следовательно, при реализации компилятора iar (размер блока 56 байтов) издержки 7% (в 32-битной системе) будут выше, чем при использовании std :: vector или массива. В реализации gcc в блоке поместятся 9 объектов (504 байта), в то время как для каждого блока требуется 512 + 4 байта, что на 2% больше.

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

Для std :: list потребуются 2 указателя на структуру, что в моем случае составляет 14% на 32-битных системах.

1 Ответ

0 голосов
/ 25 июня 2018
  1. std::vector

    ... память может быть сегментирована?

    Нет, std::vectorвыделяет непрерывную память, как описано в этой ссылке.Массивы также являются смежными, но вы также можете использовать вектор для этого.

  2. std::deque сегментирован, что, как вы сказали, вам не нужно.Или вы хотите избежать одного большого выделенного блока?Это не ясно.

    В любом случае, он не имеет никакого преимущества перед вектором, если вам действительно нужен кольцевой буфер (потому что вы все равно никогда не будете добавлять / удалять элементы спереди / сзади), и вы не можете контролироватьразмер блока.

  3. std::queue

    ... Правда ли, что во многих реализациях очередь добавляется так же, какdeque?

    Да, это значение по умолчанию в всех реализациях.См. Связанную документацию или любую приличную книгу.

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

  4. 'std :: map`

    ... итерация по карте может быть быстрее, потому что она уже отсортирована?

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

    ... Требования к памяти карты?

    Выше.К каждому элементу добавлен размер узла (не менее пары указателей).

...