[英]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_bitset
上reset
也可以編譯為memset
,而使用std::vector<bool>
可能不會得到它。 例如,請參閱https://godbolt.org/z/aqSGCi
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.