简体   繁体   English

如何将向量归零<bool> ?

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

I have a vector<bool> and I'd like to zero it out.我有一个vector<bool>并且我想将其归零。 I need the size to stay the same.我需要尺寸保持不变。

The normal approach is to iterate over all the elements and reset them.通常的方法是迭代所有元素并重置它们。 However, vector<bool> is a specially optimized container that, depending on implementation, may store only one bit per element.然而, vector<bool>是一个特别优化的容器,根据实现的不同,每个元素可能只存储一位。 Is there a way to take advantage of this to clear the whole thing efficiently?有没有办法利用这一点来有效地清除整个事情?

bitset , the fixed-length variant, has the set function. bitset是固定长度的变体,具有set功能。 Does vector<bool> have something similar? vector<bool>有类似的东西吗?

There seem to be a lot of guesses but very few facts in the answers that have been posted so far, so perhaps it would be worthwhile to do a little testing.到目前为止发布的答案中似乎有很多猜测,但事实很少,因此也许值得进行一些测试。

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

So this creates a vector, sets some randomly selected bits in it, counts them, and clears them (and repeats).所以这会创建一个向量,在其中设置一些随机选择的位,对它们进行计数,然后清除它们(并重复)。 The setting/counting/printing is done to ensure that even with aggressive optimization, the compiler can't/won't optimize out our code to clear the vector.设置/计数/打印是为了确保即使进行了积极的优化,编译器也不能/不会优化我们的代码来清除向量。

I found the results interesting, to say the least.我发现结果很有趣,至少可以说。 First the result with VC++:首先是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

So, with VC++, the fastest method is what you'd probably initially think of as the most naive -- a loop that assigns to each individual item.因此,对于 VC++,最快的方法可能是您最初认为最幼稚的方法——分配给每个单独项目的循环。 With g++, the results are just a tad different though:使用 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

Here, the loop is (by far) the slowest method (and the others are basically tied -- the 1 ms difference in speed isn't really repeatable).在这里,循环是(到目前为止)最慢的方法(而其他方法基本上是绑定的——1 毫秒的速度差异并不是真正可重复的)。

For what it's worth, in spite of this part of the test showing up as much faster with g++, the overall times were within 1% of each other (4.944 seconds for VC++, 4.915 seconds for g++).值得一提的是,尽管测试的这一部分在使用 g++ 时表现更快,但总体时间彼此相差在 1% 以内(VC++ 为 4.944 秒,g++ 为 4.915 秒)。

Try尝试

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

Have a look at this link: http://www.cplusplus.com/reference/vector/vector/assign/看看这个链接: http : //www.cplusplus.com/reference/vector/vector/assign/

Or the following或以下

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

You are out of luck.你倒霉了。 std::vector<bool> is a specialization that apparently does not even guarantee contiguous memory or random access iterators (or even forward?!), at least based on my reading of cppreference -- decoding the standard would be the next step. std::vector<bool>是一种专业化,显然甚至不能保证连续内存或随机访问迭代器(甚至向前?!),至少基于我对 cppreference 的阅读——解码标准将是下一步。

So write implementation specific code, pray and use some standard zeroing technique, or do not use the type.所以编写实现特定的代码,祈祷并使用一些标准的归零技术,或者不使用类型。 I vote 3.我投3票。

The recieved wisdom is that it was a mistake, and may become deprecated.收到的智慧是这是一个错误,可能会被弃用。 Use a different container if possible.如果可能,请使用不同的容器。 And definitely do not mess around with the internal guts, or rely on its packing.绝对不要乱动内部胆量,或依赖其包装。 Check if you have dynamic bitset in your std library mayhap, or roll your own wrapper around std::vector<unsigned char> .检查您的std库中是否有动态位集可能会发生,或者在std::vector<unsigned char>周围滚动您自己的包装器。

Use the std::vector<bool>::assign method, which is provided for this purpose.使用为此目的提供的std::vector<bool>::assign方法。 If an implementation is specific for bool , then assign , most likely, also implemented appropriately.如果一个实现是特定于bool ,那么assign很可能也被适当地实现了。

I ran into this as a performance issue recently.我最近遇到了这个作为性能问题。 I hadn't tried looking for answers on the web but did find that using assignment with the constructor was 10x faster using g++ O3 (Debian 4.7.2-5) 4.7.2.我没有尝试在网上寻找答案,但确实发现使用 g++ O3 (Debian 4.7.2-5) 4.7.2 使用构造函数进行赋值的速度提高了 10 倍。 I found this question because I was looking to avoid the additional malloc .我发现这个问题是因为我想避免额外的malloc Looks like the assign is optimized as well as the constructor and about twice as good in my benchmark.看起来赋值和构造函数都得到了优化,在我的基准测试中大约是它的两倍。

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

So, I wouldn't say to shy away from using the specialization of vector<bool> ;所以,我不会说要回避使用vector<bool>的专业化; just be very cognizant of the bit vector representation.只是非常了解位向量表示。

If you're able to switch from vector<bool> to a custom bit vector representation, then you can use a representation designed specifically for fast clear operations, and get some potentially quite significant speedups (although not without tradeoffs).如果您能够从vector<bool>切换到自定义位向量表示,那么您可以使用专为快速清除操作设计的表示,并获得一些潜在的非常显着的加速(尽管并非没有折衷)。

The trick is to use integers per bit vector entry and a single 'rolling threshold' value that determines which entries actually then evaluate to true.诀窍是使用每个位向量条目的整数和单个“滚动阈值”值,该值确定哪些条目实际评估为真。

You can then clear the bit vector by just increasing the single threshold value, without touching the rest of the data (until the threshold overflows).然后,您只需增加单个阈值即可清除位向量,而无需触及其余数据(直到阈值​​溢出)。

A more complete write up about this, and some example code, can be found here .可以在此处找到关于此的更完整的文章和一些示例代码。

It seems that one nice option hasn't been mentioned yet:似乎还没有提到一个不错的选择:

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

The STL implementer will supposedly have picked the most efficient means of zeroising, so we don't even need to know which particular method that might be.据说 STL 实现者会选择最有效的归零方法,因此我们甚至不需要知道可能是哪种特定方法。 And this works with real vectors as well (think templates), not just the std::vector<bool> monstrosity.这也适用于实向量(想想模板),而不仅仅是std::vector<bool>怪物。

There can be a minuscule added advantage for reused buffers in loops (eg sieves, whatever), where you simply resize to whatever will be needed for the current round, instead of to the original size.在循环中重用缓冲区(例如筛子等)可能有一个微不足道的附加优势,您只需将大小调整为当前回合所需的大小,而不是原始大小。

As an alternative to std::vector<bool> , check out boost::dynamic_bitset ( https://www.boost.org/doc/libs/1_72_0/libs/dynamic_bitset/dynamic_bitset.html ).作为std::vector<bool>的替代方案,请查看boost::dynamic_bitset ( https://www.boost.org/doc/libs/1_72_0/libs/dynamic_bitset/dynamic_bitset.html )。 You can zero one (ie, set each element to false) out by calling the reset() member function.您可以通过调用reset()成员函数将其reset()即,将每个元素设置为 false)。

Like clearing, say, std::vector<int> , reset on a boost::dynamic_bitset can also compile down to a memset , whereas you probably won't get that with std::vector<bool> .就像清除std::vector<int> ,在boost::dynamic_bitsetreset也可以编译为memset ,而使用std::vector<bool>可能不会得到它。 For example, see https://godbolt.org/z/aqSGCi例如,请参阅https://godbolt.org/z/aqSGCi

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM