Подтвердить что ты не робот

Как обнулить вектор <bool>?

У меня есть vector<bool>, и я бы хотел его обнулить. Мне нужен размер, чтобы оставаться тем же.

Обычный подход - это перебрать все элементы и reset их. Однако vector<bool> представляет собой специально оптимизированный контейнер, который, в зависимости от реализации, может хранить только один бит на элемент. Есть ли способ воспользоваться этим, чтобы эффективно очистить все это?

bitset, вариант с фиксированной длиной, имеет функцию set. Имеет ли vector<bool> нечто подобное?

4b9b3361

Ответ 1

Вам не повезло. std::vector<bool> - это специализация, которая, по-видимому, даже не гарантирует непрерывную память или итераторы произвольного доступа (или даже переадресация?!), по крайней мере, на основе моего чтения cppreference - декодирование стандарта станет следующим шагом.

Так напишите конкретный код реализации, помолитесь и используйте стандартную методику обнуления или не используйте тип. Я голосую 3.

Полученная мудрость заключается в том, что она была ошибкой и может стать устаревшей. Если возможно, используйте другой контейнер. И определенно не возитесь с внутренними кишками, или полагайтесь на свою упаковку. Проверьте, есть ли у вас динамический бит в вашей библиотеке std mayhap, или сверните свою собственную оболочку вокруг std::vector<unsigned char>.

Ответ 2

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

#include <vector>
#include <iostream>
#include <time.h>

int seed(std::vector<bool> &b) {
    srand(1);
    for (int i = 0; i < b.size(); i++)
        b[i] = ((rand() & 1) != 0);
    int count = 0;
    for (int i = 0; i < b.size(); i++)
    if (b[i])
        ++count;
    return count;
}

int main() {
    std::vector<bool> bools(1024 * 1024 * 32);

    int count1= seed(bools);
    clock_t start = clock();
    bools.assign(bools.size(), false);
    double using_assign = double(clock() - start) / CLOCKS_PER_SEC;

    int count2 = seed(bools);
    start = clock();
    for (int i = 0; i < bools.size(); i++)
        bools[i] = false;
    double using_loop = double(clock() - start) / CLOCKS_PER_SEC;

    int count3 = seed(bools);
    start = clock();
    size_t size = bools.size();
    bools.clear();
    bools.resize(size); 
    double using_clear = double(clock() - start) / CLOCKS_PER_SEC;

    int count4 = seed(bools);
    start = clock();
    std::fill(bools.begin(), bools.end(), false);
    double using_fill = double(clock() - start) / CLOCKS_PER_SEC;


    std::cout << "Time using assign: " << using_assign << "\n";
    std::cout << "Time using loop: " << using_loop << "\n";
    std::cout << "Time using clear: " << using_clear << "\n";
    std::cout << "Time using fill: " << using_fill << "\n";
    std::cout << "Ignore: " << count1 << "\t" << count2 << "\t" << count3 << "\t" << count4 << "\n";
}

Итак, это создает вектор, устанавливает в него некоторые случайно выбранные биты, подсчитывает их и очищает (и повторяет). Настройка/подсчет/печать выполняется для обеспечения того, что даже при агрессивной оптимизации компилятор не может/не будет оптимизировать наш код, чтобы очистить вектор.

Я нашел результаты интересными, мягко говоря. Сначала результат с VС++:

Time using assign: 0.141
Time using loop: 0.068
Time using clear: 0.141
Time using fill: 0.087
Ignore: 16777216        16777216        16777216        16777216

Таким образом, с помощью VС++ самый быстрый метод - это то, что вы, вероятно, изначально считаете самым наивным - цикл, который присваивает каждому отдельному элементу. С g++ результаты только немного отличаются, хотя:

Time using assign: 0.002
Time using loop: 0.08
Time using clear: 0.002
Time using fill: 0.001
Ignore: 16777216        16777216        16777216        16777216

Здесь цикл (безусловно) самый медленный метод (и другие в основном связаны - разница в скорости 1 мс на самом деле не повторяется).

Для того, что стоит, несмотря на то, что эта часть теста проявляется быстрее с g++, общее время было в пределах 1% друг от друга (4.944 секунды для VС++, 4.915 секунд для g++).

Ответ 4

Используйте метод std::vector<bool>::assign, который предоставляется для этой цели. Если реализация имеет значение для bool, то assign, скорее всего, также будет реализована соответствующим образом.

Ответ 5

Если вы можете переключиться с vector<bool> на представление пользовательского битового вектора, вы можете использовать представление, разработанное специально для быстрых ясных операций, и получить некоторые потенциально довольно значительные ускорения (хотя и не без компромиссов).

Трюк состоит в том, чтобы использовать целые числа для записи вектора бит и одно значение "порогового порога", которое определяет, какие записи на самом деле затем оцениваются как истинные.

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

Более полная запись об этом и примерный код можно найти здесь.

Ответ 6

Я столкнулся с этим как проблема производительности в последнее время. Я не пробовал искать ответы в Интернете, но нашел, что использование назначения с конструктором было в 10 раз быстрее, используя g++ O3 (Debian 4.7.2-5) 4.7.2. Я нашел этот вопрос, потому что я старался избегать дополнительных malloc. Похоже, что назначение оптимизировано, а также конструктор и примерно в два раза лучше в моем тесте.

unsigned sz = v.size(); for (unsigned ii = 0; ii != sz; ++ii) v[ii] = false;
v = std::vector(sz, false); // 10x faster
v.assign(sz, false); >      // 20x faster

Итак, я бы не сказал, чтобы уклониться от использования специализации vector<bool>; просто будьте очень осведомлены о представлении вектора бит.

Ответ 7

Кажется, что еще один хороший вариант еще не упоминался:

auto size = v.size();
v.resize(0);
v.resize(size);

Предполагается, что разработчик STL выбрал наиболее эффективные средства обнуления, поэтому нам даже не нужно знать, какой именно метод может быть. И это также работает с реальными векторами (думаю, шаблоны), а не только std::vector<bool> монстра.

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