Какой лучший контейнер С++ для хранения двоичных данных и доступа к ним?
std::vector<unsigned char>
или
std::string
Является ли более эффективным, чем другой?
Является ли это более "правильным" использованием?
Какой лучший контейнер С++ для хранения двоичных данных и доступа к ним?
std::vector<unsigned char>
или
std::string
Является ли более эффективным, чем другой?
Является ли это более "правильным" использованием?
Вы должны предпочесть std::vector
над std::string
. В обычных случаях оба решения могут быть почти эквивалентными, но std::string
разработаны специально для строк и строковых манипуляций, и это не ваше намеренное использование.
Оба правильные и одинаково эффективные. Использование одного из них вместо простого массива - только для облегчения управления памятью и передачи их в качестве аргумента.
Я использую вектор, потому что намерение более ясно, чем со строкой.
Изменить: Стандарт С++ 03 не гарантирует совместимость памяти std::basic_string
. Однако с практической точки зрения нет коммерческих несмежных реализаций. С++ 0x установлен в стандартизировать этот факт.
Является ли более эффективным, чем другой?
Это неправильный вопрос.
Это более "правильное" использование?
Это правильный вопрос.
Это зависит. Как используются данные? Если вы собираетесь использовать данные в строке, например fashon, тогда вы должны выбрать std::string, поскольку использование std::vector может запутать последующих сопровождающих. Если, с другой стороны, большая часть манипуляций с данными выглядит как простая математика или вектор, а затем более подходит std::vector.
Это комментарий к ответу 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;
}
В течение самого долгого времени я согласился с большинством ответов здесь. Однако, только сегодня это поразило меня, почему было бы разумнее использовать std::string
более std::vector<unsigned char>
.
Как большинство согласен, использование одного из них будет работать отлично. Но часто время, данные файла могут быть в текстовом формате (более распространены теперь, когда XML стал основным). Это облегчает просмотр в отладчике, когда он становится уместным (и эти отладчики часто позволят вам перемещаться по байтам строки в любом случае). Но что более важно, многие существующие функции, которые можно использовать в строке, могут быть легко использованы для файлов/двоичных данных. Я обнаружил, что пишу несколько функций для обработки как строк, так и байт-массивов, и понял, насколько бессмысленно все это.
Что касается удобочитаемости, я предпочитаю std::vector. std::vector должен быть контейнером по умолчанию в этом случае: намерение понятнее и, как уже было сказано другими ответами, в большинстве реализаций оно также более эффективно.
В одном случае я предпочитал std::string более std::vector. Давайте посмотрим на подписи их конструкторов перемещения в С++ 11:
string (string && str) noexcept;
В этом случае мне действительно нужен конструктор move noexcept. std::string предоставляет его, а std::vector - нет.
Если вы просто хотите сохранить свои двоичные данные, вы можете использовать bitset
, который оптимизирует пространство для размещения. В противном случае используйте vector
, поскольку это более подходит для вашего использования.
Сравните это 2 и выберите себя, что более конкретно для вас. Оба они очень надежны, работают с алгоритмами STL... Выберите себя, который более эффективен для вашей задачи.
Лично я предпочитаю std::string, потому что string:: data() гораздо более интуитивно понятен для меня, когда я хочу, чтобы мой двоичный буфер вернулся в C-совместимую форму. Я знаю, что элементы вектора гарантированно хранятся, и их выполнение в коде несколько неудобно.
Это решение стиля, которое отдельный разработчик или команда должны сделать для себя.