簡體   English   中英

如何將向量歸零<bool> ?

[英]How to zero a vector<bool>?

我有一個vector<bool>並且我想將其歸零。 我需要尺寸保持不變。

通常的方法是迭代所有元素並重置它們。 然而, vector<bool>是一個特別優化的容器,根據實現的不同,每個元素可能只存儲一位。 有沒有辦法利用這一點來有效地清除整個事情?

bitset是固定長度的變體,具有set功能。 vector<bool>有類似的東西嗎?

到目前為止發布的答案中似乎有很多猜測,但事實很少,因此也許值得進行一些測試。

#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";
}

所以這會創建一個向量,在其中設置一些隨機選擇的位,對它們進行計數,然后清除它們(並重復)。 設置/計數/打印是為了確保即使進行了積極的優化,編譯器也不能/不會優化我們的代碼來清除向量。

我發現結果很有趣,至少可以說。 首先是VC++的結果:

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

因此,對於 VC++,最快的方法可能是您最初認為最幼稚的方法——分配給每個單獨項目的循環。 使用 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% 以內(VC++ 為 4.944 秒,g++ 為 4.915 秒)。

嘗試

v.assign(v.size(), false);

看看這個鏈接: http : //www.cplusplus.com/reference/vector/vector/assign/

或以下

std::fill(v.begin(), v.end(), 0)

你倒霉了。 std::vector<bool>是一種專業化,顯然甚至不能保證連續內存或隨機訪問迭代器(甚至向前?!),至少基於我對 cppreference 的閱讀——解碼標准將是下一步。

所以編寫實現特定的代碼,祈禱並使用一些標准的歸零技術,或者不使用類型。 我投3票。

收到的智慧是這是一個錯誤,可能會被棄用。 如果可能,請使用不同的容器。 絕對不要亂動內部膽量,或依賴其包裝。 檢查您的std庫中是否有動態位集可能會發生,或者在std::vector<unsigned char>周圍滾動您自己的包裝器。

使用為此目的提供的std::vector<bool>::assign方法。 如果一個實現是特定於bool ,那么assign很可能也被適當地實現了。

我最近遇到了這個作為性能問題。 我沒有嘗試在網上尋找答案,但確實發現使用 g++ O3 (Debian 4.7.2-5) 4.7.2 使用構造函數進行賦值的速度提高了 10 倍。 我發現這個問題是因為我想避免額外的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>的專業化; 只是非常了解位向量表示。

如果您能夠從vector<bool>切換到自定義位向量表示,那么您可以使用專為快速清除操作設計的表示,並獲得一些潛在的非常顯着的加速(盡管並非沒有折衷)。

訣竅是使用每個位向量條目的整數和單個“滾動閾值”值,該值確定哪些條目實際評估為真。

然后,您只需增加單個閾值即可清除位向量,而無需觸及其余數據(直到閾值​​溢出)。

可以在此處找到關於此的更完整的文章和一些示例代碼。

似乎還沒有提到一個不錯的選擇:

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

據說 STL 實現者會選擇最有效的歸零方法,因此我們甚至不需要知道可能是哪種特定方法。 這也適用於實向量(想想模板),而不僅僅是std::vector<bool>怪物。

在循環中重用緩沖區(例如篩子等)可能有一個微不足道的附加優勢,您只需將大小調整為當前回合所需的大小,而不是原始大小。

作為std::vector<bool>的替代方案,請查看boost::dynamic_bitset ( https://www.boost.org/doc/libs/1_72_0/libs/dynamic_bitset/dynamic_bitset.html )。 您可以通過調用reset()成員函數將其reset()即,將每個元素設置為 false)。

就像清除std::vector<int> ,在boost::dynamic_bitsetreset也可以編譯為memset ,而使用std::vector<bool>可能不會得到它。 例如,請參閱https://godbolt.org/z/aqSGCi

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM