Изменяемый тип контейнера буферного символа для C ++ - PullRequest
0 голосов
/ 23 августа 2011

Я использую libcurl (библиотеку передачи HTTP) с C ++ и пытаюсь загрузить файлы с удаленных HTTP-серверов. Когда файл загружен, моя функция обратного вызова вызывается несколько раз (например, каждые 10 КБ), чтобы отправить мне данные буфера.

В основном мне нужно что-то вроде "string bufer", структуры данных для добавления буфера char к существующей строке. В C я выделяю (malloc) char*, а затем по мере поступления новых буферов я realloc, а затем memcpy, чтобы я мог легко скопировать свой буфер в массив с измененным размером.

В C есть несколько решений для достижения этой цели.

  1. Я могу продолжать использовать malloc, realloc, memcpy, но я почти уверен, что они не рекомендуются в C ++.
  2. Я могу использовать vector<char>.
  3. Я могу использовать stringstream.

Мои сценарии использования: я добавляю несколько тысяч элементов (char s) за раз, и после того, как все закончится (загрузка завершена), я прочитаю все сразу. Но в будущем мне могут понадобиться такие опции, как seek (это легко сделать в решении с массивами (1)), но сейчас это низкий приоритет.

Что мне использовать?

Ответы [ 6 ]

1 голос
/ 23 августа 2011

Думаю, я бы использовал deque<char>.Интерфейс тот же, что и у vector, и вектор будет работать, но вектор должен копировать все данные каждый раз, когда добавление превышает его существующую емкость.Рост экспоненциальный, но вы все равно ожидаете около log N перераспределений, где N - это количество блоков данных одинакового размера, которые вы добавляете.Deque не перераспределяет, поэтому он является предпочтительным контейнером в тех случаях, когда вектор должен был перераспределяться несколько раз.данные достаточно просты:

mydeque.insert(mydeque.end(), buf, buf + len);

Чтобы получить строку в конце, если вам нужна:

std::string mystring(mydeque.begin(), mydeque.end());

Я не совсем уверен, что вы подразумеваете под seek,но, очевидно, deque может быть доступен по индексу или итератору, так же как и vector.

Другая возможность, однако, заключается в том, что если вы ожидаете длину содержимого в начале загрузки, вы можете использоватьvector и reserve() достаточно места для данных перед началом, что позволяет избежать перераспределения.Это зависит от того, какие HTTP-запросы вы делаете, и к каким серверам, поскольку некоторые HTTP-ответы будут использовать кусочную кодировку и не будут указывать размер заранее.

1 голос
/ 23 августа 2011

Если вам просто нужно добавить буферы символов, вы также можете просто использовать std::string и функцию-член append. Вдобавок к этому stringstream предоставляет вам форматирование, функциональность, так что вы можете добавлять числа, отступы и т. Д., Но из вашего описания вам это не нужно.

1 голос
/ 23 августа 2011

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

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

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

1 голос
/ 23 августа 2011

Я бы пошел на stringstream. Просто вставьте в него, как только вы получите данные, и когда вы закончите, вы можете извлечь из него полный std::string. Я не понимаю, почему вы хотите seek в массив? В любом случае, если вы знаете размер блока, вы можете вычислить, куда в строке ушел соответствующий блок.

0 голосов
/ 23 августа 2011

Создайте свой собственный класс Buffer, чтобы абстрагироваться от деталей хранилища.На вашем месте я бы, вероятно, реализовал буфер на основе std::vector<char>.

0 голосов
/ 23 августа 2011

Я бы использовал vector<char>. Но все они будут работать даже с поиском, так что ваш вопрос действительно стильный, и там нет однозначных ответов.

...