Здесь многое зависит от того, сколько булевых значений вы работаете.
Оба битового набора и vector<bool>
обычно используют упакованное представление, в котором булевский хранится как только один бит.
С одной стороны, это накладывает некоторые накладные расходы в виде манипуляции с битами для доступа к одному значению.
С другой стороны, это также означает, что в ваш кеш поместится еще много ваших булевых элементов.
Если вы используете много булевых элементов (например, реализуя решетку Eratosthenes), при установке большего количества из них в кеше почти всегда будет получена чистая прибыль. Сокращение использования памяти принесет вам гораздо больше, чем потеря бит.
Большинство аргументов против std::vector<bool>
возвращаются к тому факту, что он не является стандартным контейнером (т. Е. Не соответствует требованиям к контейнеру). ИМО, это в основном вопрос ожиданий - так как он говорит vector
, многие люди ожидают, что это контейнер (другие типы векторов), и они часто отрицательно реагируют на то, что vector<bool>
не является контейнером.
Если вы используете вектор так, чтобы на самом деле требовать, чтобы он был контейнером, то вы, вероятно, захотите использовать какую-либо другую комбинацию - либо deque<bool>
, либо vector<char>
может работать нормально. Подумайте прежде чем сделать это, хотя - есть много советов (паршивая, IMO), что vector<bool>
следует избегать в целом, с небольшим или без объяснения причин, почему следует избегать вообще, или при каких обстоятельствах это делает реальное разница с вами.
Да, бывают ситуации, когда что-то еще будет работать лучше. Если вы находитесь в одной из таких ситуаций, использование чего-то другого - это, безусловно, хорошая идея. Но сначала убедитесь, что вы действительно в одной из этих ситуаций. Любой, кто скажет вам (например), что «Herb говорит, что вы должны использовать vector<char>
», без большого объяснения о связанных с этим компромиссах не следует доверять.
Давайте дадим реальный пример. Так как это было упомянуто в комментариях, давайте рассмотрим Решето Эратосфена:
#include <vector>
#include <iostream>
#include <iterator>
#include <chrono>
unsigned long primes = 0;
template <class bool_t>
unsigned long sieve(unsigned max) {
std::vector<bool_t> sieve(max, false);
sieve[0] = sieve[1] = true;
for (int i = 2; i < max; i++) {
if (!sieve[i]) {
++primes;
for (int temp = 2 * i; temp < max; temp += i)
sieve[temp] = true;
}
}
return primes;
}
// Warning: auto return type will fail with older compilers
// Fine with g++ 5.1 and VC++ 2015 though.
//
template <class F>
auto timer(F f, int max) {
auto start = std::chrono::high_resolution_clock::now();
primes += f(max);
auto stop = std::chrono::high_resolution_clock::now();
return stop - start;
}
int main() {
using namespace std::chrono;
unsigned number = 100000000;
auto using_bool = timer(sieve<bool>, number);
auto using_char = timer(sieve<char>, number);
std::cout << "ignore: " << primes << "\n";
std::cout << "Time using bool: " << duration_cast<milliseconds>(using_bool).count() << "\n";
std::cout << "Time using char: " << duration_cast<milliseconds>(using_char).count() << "\n";
}
Мы использовали достаточно большой массив, который мы можем ожидать, большая часть его занимает основную память. Я также пошел в небольшую боль, чтобы гарантировать, что только вещь, которая меняется от одного вызова, а другой является использование vector<char>
VS. vector<bool>
. Вот некоторые результаты. Сначала с VC++ 2015:
ignore: 34568730
Time using bool: 2623
Time using char: 3108
... то время, используя г ++ 5.1:
ignore: 34568730
Time using bool: 2359
Time using char: 3116
Очевидно, что vector<bool>
победы в обоих случаях - примерно на 15% с VC++, и более чем на 30% с gcc. Также обратите внимание, что в этом случае я выбрал размер, чтобы показать vector<char>
в довольно благоприятном свете. Если, например, я уменьшаю number
100000000
от до 10000000
, то разница во времени становится гораздо больше:
ignore: 3987474
Time using bool: 72
Time using char: 249
Хотя я не сделал много работы, чтобы подтвердить, что я думаю, что в этом случае , версия с использованием vector<bool>
является сохранение достаточно мест, что массив соответствует полностью в кэше, в то время как vector<char>
достаточно большая, чтобы переполнить кэш, и привлечь большое количество основного доступа к памяти.
Поскольку это зависит от того, как вы его используете, относительный размер вашего контейнера и кеш-памяти процессора, а также, возможно, различные другие факторы ... что произошло, когда вы сравнили его? – Useless