2009-01-13 3 views
44

В общем, что является лучшим способом хранения двоичных данных на C++? Параметры, насколько я могу судить, в значительной степени сводятся к использованию строк или вектора <char> s. (Я опускаю возможность char * s и malloc(), так как я имею в виду конкретно C++).«Правильный» способ хранения двоичных данных с помощью C++/STL

Обычно я просто использую строку, однако я не уверен, есть ли накладные расходы, которые у меня отсутствуют, или преобразования, которые STL делает внутренне, что может испортить разумность двоичных данных. У кого-нибудь есть указатели (хар) по этому поводу? Предложения или предпочтения так или иначе?

ответ

38

вектор char приятный, потому что память соприкасается. Поэтому вы можете использовать его с большим количеством C API, таких как сокеты berkley или файловые API. Вы можете сделать следующее, например:

std::vector<char> vect; 
    ... 
    send(sock, &vect[0], vect.size()); 

и он будет работать нормально.

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

Недостатком является изменение размера не очень эффективно (изменение размера или предубеждение предусмотрительно) и удаление из передней части массива также будет очень незначительным. Если вам нужно, скажем, выставить только один или два символа в момент времени перед структурой данных очень часто, копируя их в deque, прежде чем эта обработка может быть вариантом. Это стоит вам копия, а память deque не соприкасается, поэтому вы не можете просто передать указатель на C API.

Нижняя линия, узнайте о структурах данных и их компромиссах перед погружением, однако вектор символа, как правило, я вижу в обычной практике.

+2

хорошо ответ. для части обучения: я нашел красивую картинку, показывающую использование контейнеров некоторое время назад, и встроил ее в этот ответ: http://stackoverflow.com/questions/366432/extending-stdlist#366710 –

6

Для этого я тоже использую std::string, и у меня никогда не было проблем с этим.

Один «указатель», который вчера получил резкое напоминание в куске кода: при создании строки из блока двоичных данных используйте форму конструктора , а не форму std::string(ptr, offset, length) - последняя делает предположение о том, что указатель указывает на строку стиля С и игнорирует что-либо после первого нулевого символа (он копирует «до» указанные length, а не length символов).

+0

Хммм. Согласно http://www.cplusplus.com/reference/string/string/string.html, std :: string (char * ptr, offset, length) ctor должен копировать * все * длины байтов, включая нулевые байты. Это std :: string (string const &, offset, length) ctor, который копирует * до * длины байтов. –

+0

Это побудило меня снова просмотреть его, и кажется, что * есть * no std :: string (char * ptr, offset, length) constructor. Конструктор, который принимает смещение и длину, требует в качестве первого параметра std :: string, поэтому он автоматически строил строку из байтов, что и урезало ее. –

+0

Вы правы. Извините, я имел в виду, что std :: string (char * ptr, size_t length) ctor должен скопировать все байты. –

3

Вы обязательно должны использовать контейнер, но контейнер, который вы хотите использовать, зависит от вашего приложения.

У Chars есть несколько свойств, которые делают их полезными для хранения двоичных данных: стандарт запрещает «заполнение» для символьного типа данных, что важно, поскольку это означает, что вы не получите мусор в своем двоичном макете. Каждому символу также гарантированно будет один байт, что делает его единственным простым старым типом данных (POD) с заданной шириной (все остальные указаны в терминах верхней и/или нижней границ).

Обсуждение подходящего контейнера stl, в котором хранятся символы, хорошо описано Doug выше. Какой вам нужен, полностью зависит от вашего варианта использования. Если вы просто держите блок данных, которые вы перебираете, без какого-либо специального поиска, добавления/удаления или необходимости сплайсинга, я бы предпочел вектор, который делает ваши намерения более ясными, чем std :: string, которые многие библиотеки и функции будут принимать содержит строку c-style с нулевым завершением.

8

Самая большая проблема с std :: string заключается в том, что текущий стандарт не гарантирует, что его базовое хранилище смежно.Однако нет известных реализаций STL, где строка не является смежной, поэтому на практике она, вероятно, не подведет. Фактически, новый стандарт C++ 0x исправит эту проблему, указав, что std :: string использует непрерывный буфер, такой как std :: vector.

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

Сказанное, я рекомендую также вектор.

Смежные вопросы