Какой контейнер С++ лучше для хранения двоичных данных и доступа к ним?
std::vector<unsigned char>
or
std::string
Один из них более эффективен, чем другой?
Является ли один из них более «правильным»?
Какой контейнер С++ лучше для хранения двоичных данных и доступа к ним?
std::vector<unsigned char>
or
std::string
Один из них более эффективен, чем другой?
Является ли один из них более «правильным»?
Вы должны предпочесть std::vector
вместо std::string
. В общих случаях оба решения могут быть почти эквивалентны, но std::string
s разработаны специально для строк и манипуляций со строками, и это не ваше предполагаемое использование.
char_traits<char>
, а со стандартной специализацией присваивание, сравнение и упорядочение определяются как эквивалент встроенного типа char.
- person David Rodríguez - dribeas; 13.10.2009
std::vector
лучше соответствует тому, что вы хотите от буфера, поэтому, если только из-за более ясного намерения (как указывает fnieto в своем ответе), я бы предпочел std::vector
- person David Rodríguez - dribeas; 14.10.2009
Оба варианта правильны и одинаково эффективны. Использование одного из них вместо простого массива предназначено только для облегчения управления памятью и передачи их в качестве аргумента.
Я использую вектор, потому что намерение более ясно, чем со строкой.
Изменить: стандарт C++03 не гарантирует непрерывность памяти std::basic_string
. Однако с практической точки зрения коммерческих несмежных реализаций не существует. C++0x установлен на стандартизировать этот факт< /а>.
Является ли один более эффективным, чем другой?
Это неправильный вопрос.
Является ли одно из них более «правильным» использованием?
Это правильный вопрос.
Это зависит от ситуации. Как используются данные? Если вы собираетесь использовать данные в виде строки, такой как fashon, вам следует выбрать std::string, так как использование std::vector может запутать последующих сопровождающих. Если, с другой стороны, большая часть манипуляций с данными выглядит как простая математика или вектор, то более подходящим является std::vector.
Долгое время я соглашался с большинством ответов здесь. Однако только сегодня меня осенило, почему было бы разумнее использовать std::string
вместо std::vector<unsigned char>
.
Большинство согласны с тем, что использование любого из них будет работать нормально. Но часто файловые данные могут быть в текстовом формате (что более распространено сейчас, когда XML стал мейнстримом). Это упрощает просмотр в отладчике, когда это становится уместным (и эти отладчики все равно часто позволяют вам перемещаться по байтам строки). Но что более важно, многие существующие функции, которые можно использовать со строкой, можно легко использовать с файловыми/двоичными данными. Я обнаружил, что пишу несколько функций для обработки как строк, так и массивов байтов, и понял, насколько все это бессмысленно.
Это комментарий к ответу dribeas. Я пишу это как ответ, чтобы иметь возможность форматировать код.
Это функция сравнения char_traits, и поведение вполне нормальное:
static bool
lt(const char_type& __c1, const char_type& __c2)
{ return __c1 < __c2; }
template<typename _CharT>
int
char_traits<_CharT>::
compare(const char_type* __s1, const char_type* __s2, std::size_t __n)
{
for (std::size_t __i = 0; __i < __n; ++__i)
if (lt(__s1[__i], __s2[__i]))
return -1;
else if (lt(__s2[__i], __s1[__i]))
return 1;
return 0;
}
assign
, eq
и lt
должны быть определены как встроенные операторы =, == и ‹ для типа char
.
- person David Rodríguez - dribeas; 13.10.2009
Что касается удобочитаемости, я предпочитаю std::vector. В этом случае std::vector должен быть контейнером по умолчанию: цель более ясна и, как уже говорилось в других ответах, в большинстве реализаций она также более эффективна.
Однако однажды я предпочел std::string std::vector. Давайте посмотрим на сигнатуры их конструкторов перемещения в C++11:
строка (string&& str) без исключений;
В этом случае мне действительно понадобился конструктор перемещения noexcept. std::string предоставляет его, а std::vector — нет.
Если вы просто хотите сохранить свои двоичные данные, вы можете использовать bitset
, который оптимизирует выделение пространства. В противном случае выберите vector
, так как он больше подходит для вашего использования.
vector
лучше.
- person Jacob; 13.10.2009
bitset
эффективен при хранении двоичных данных — я никогда не говорил, что bitset
является контейнером STL. И создать эту довольно большую строку (которая будет использовать unsigned char
, кстати) тривиально. Кроме того, все, что я видел до сих пор (пример кода в моем компиляторе, поиск в Google и эффективный STL (стр. 70)) указывает на то, что набор битов действительно хранит двоичные данные эффективно. И да, есть лучший способ хранения двоичных данных, и это bitset
— вы пробовали его на своем компиляторе? Всего две строчки кода.
- person Jacob; 13.10.2009
not
, поскольку это то же самое, что и сохранение данных, вы можете использовать bitset::to_string
. И да, вам нужна строка размером 10 МБ — в этом весь смысл использования битового набора. Предположим, у вас есть массив битов, который вы получили в виде беззнаковых символов, возможно, после какой-то логической операции, и он составляет 10 МБ, и вы хотите сохранить его в памяти - что вы делаете? bitset
!
- person Jacob; 13.10.2009
std::vector<bool>
— это специализация, оптимизированная для пространства, а не то, что комитет по стандарту доволен этим), поэтому в этот момент он выиграет. даже занимает больше памяти, чем набор битов.
- person David Rodríguez - dribeas; 14.10.2009
Сравните эти 2 и выберите сами, что более конкретно для вас. Оба очень надежны, работают с алгоритмами STL ... Выбирайте сами, что более эффективно для вашей задачи.
Лично я предпочитаю std::string, потому что string::data() гораздо более интуитивно понятен для меня, когда я хочу, чтобы мой двоичный буфер вернулся в C-совместимую форму. Я знаю, что векторные элементы гарантированно будут храниться непрерывно, поэтому выполнение этого в коде кажется немного тревожным.
Это стилевое решение, которое должен принять для себя отдельный разработчик или команда.