Я работаю почти исключительно в C ++ 11/14, и обычно сжимаюсь, когда вижу такой код:
std::int64_t mArray;
mArray |= someMask << 1;
Это всего лишь пример; Я говорю о побитовой манипуляции в целом. В C ++ есть ли смысл? Вышесказанное искажает сознание и подвержено ошибкам, а использование std::bitset
позволяет:
- проще изменить размер по
std::bitset
мере необходимости, настроив параметр шаблона и позволив реализации позаботиться обо всем остальном, и - тратьте меньше времени на выяснение того, что происходит (и, возможно, на ошибки), и пишите
std::bitset
так же, какstd::array
и другие контейнеры данных.
Мой вопрос есть ли причина не использовать std::bitset
поверх примитивных типов, кроме как для обратной совместимости?
c++
c++11
bitwise-operators
шест для отталкивания
источник
источник
std::bitset
фиксируется во время компиляции. Это единственный серьезный недостаток, о котором я могу думать.std::bitset
битовой манипуляции в стиле c (напримерint
), которая также исправлена во время компиляции.std::bitset
был недоступен (или известен автору), и не было причин переписывать код для использованияstd::bitset
.bitset
один, но небольшой вектор или наборint
s (битового индекса) также могут быть допустимыми. Философия C / C ++ не скрывает эти сложности выбора от программиста.Ответы:
С логической (нетехнической) точки зрения преимущества нет.
Любой простой код C / C ++ может быть заключен в подходящую «библиотечную конструкцию». После такой упаковки вопрос «является ли это более выгодным, чем это» становится спорным вопросом.
С точки зрения скорости, C / C ++ должен позволять конструкции библиотеки генерировать код, который столь же эффективен, как и простой код, который он переносит. Это, однако, подлежит:
Используя этот вид нетехнического аргумента, любые «отсутствующие функции» могут быть добавлены кем угодно, и поэтому не считаются недостатком.
Однако встроенные требования и ограничения не могут быть преодолены с помощью дополнительного кода. Ниже я утверждаю, что размер
std::bitset
является константой времени компиляции, и, следовательно, хотя это и не считается недостатком, он все же влияет на выбор пользователя.С эстетической точки зрения (удобочитаемость, простота обслуживания и т. Д.) Есть разница.
Тем не менее, не очевидно, что
std::bitset
код сразу побеждает простой C-код. Нужно взглянуть на большие куски кода (а не на какой-то игрушечный образец), чтобы сказать,std::bitset
улучшило ли использование исходный код человеческое качество.Скорость работы с битами зависит от стиля кодирования. Стиль кодирования влияет как на манипулирование битами C / C ++, так и в равной степени применим
std::bitset
, как объясняется ниже.Если кто-то пишет код, который использует
operator []
для чтения и записи по одному биту за раз, ему придется делать это несколько раз, если нужно манипулировать более чем одним битом. То же самое можно сказать о коде в стиле C.Однако
bitset
также есть другие операторы, такие какoperator &=
,operator <<=
и т. Д., Которые работают на всю ширину набора битов. Поскольку базовый механизм часто может работать с 32-разрядными, 64-разрядными, а иногда и 128-разрядными (с SIMD) за один раз (при том же количестве циклов ЦП), код, предназначенный для использования преимуществ таких многобитовых операций может быть быстрее, чем "зацикленный" код битовой манипуляции.Общая идея называется SWAR (SIMD в регистре) и является подтемой при битовых манипуляциях.
Некоторые поставщики C ++ могут использовать
bitset
от 64 до 128 бит с SIMD. Некоторые поставщики не могут (но могут в конечном итоге сделать). Если необходимо знать, что делает библиотека вендора C ++, единственный способ - посмотреть на разборку.Что касается того,
std::bitset
есть ли ограничения, я могу привести два примера.std::bitset
должен быть известен во время компиляции. Чтобы создать массив битов с динамически выбранным размером, нужно будет использоватьstd::vector<bool>
.std::bitset
не предоставляет способ извлечения последовательного фрагмента из N битов из большегоbitset
из M битов.Первый является основополагающим, то есть для людей, которым нужны динамические размеры битов, они должны выбрать другие варианты.
Второй можно преодолеть, потому что можно написать какие-то адаптеры для выполнения задачи, даже если стандарт
bitset
не расширяемый.Существуют определенные типы расширенных операций SWAR, которые не предоставляются из коробки
std::bitset
. Можно прочитать об этих операциях на этом сайте о битовых перестановках . Как обычно, их можно реализовать самостоятельно, работая поверхstd::bitset
.По поводу обсуждения по производительности.
Одно замечание: многие люди спрашивают, почему (что-то) из стандартной библиотеки намного медленнее, чем какой-то простой код в стиле C. Я бы не стал повторять здесь предварительные знания о микробенчмаркинге, но у меня есть только один совет: убедитесь, что проводите тестирование в «режиме выпуска» (с включенной оптимизацией), и убедитесь, что код не удаляется (устранение мертвого кода) или выведен из цикла (петлево-инвариантный код движения) .
Так как в целом мы не можем сказать, правильно ли кто-то (в Интернете) делал микробенчмарки, единственный способ получить достоверное заключение - это сделать собственные микробенчмарки, документировать детали и представить для публичного просмотра и критики. Не мешает заново делать микробенчмарки, которые раньше делали другие.
источник
std::bitset
. Нет гарантии целостности памяти (instd::bitset
), что означает, что она не должна быть распределена между ядрами. Люди, которым нужно делиться ими между ядрами, будут стремиться к созданию собственной реализации. Когда данные распределяются между разными ядрами, принято выравнивать их по границе строки кэша. Невыполнение этого требования снижает производительность и создает больше ошибок, не связанных с атомарностью. У меня недостаточно знаний, чтобы дать обзор того, как построить параллелизуемую реализациюstd::bitset
.bitset
волей.Это, конечно, применимо не во всех случаях, но иногда алгоритм может зависеть от эффективности сдвоенного твила в стиле C для обеспечения значительного прироста производительности. Первый пример, который мне приходит в голову, - это использование битбордов , умных целочисленных кодировок позиций настольных игр, чтобы ускорить шахматные движки и тому подобное. Здесь фиксированный размер целочисленных типов не проблема, так как шахматные доски всегда равны 8 * 8.
Для простого примера рассмотрим следующую функцию (взятую из этого ответа Бена Джексона ), которая проверяет позицию Connect Four на победу:
источник
std::bitset
будет медленнее?