如何将矢量<bool>?</bool>归零

时间:2013-10-24 09:55:32

标签: c++ vector

我有一个vector<bool>,我想把它归零。我需要大小保持不变。

正常的方法是迭代所有元素并重置它们。但是,vector<bool>是一个specially optimized容器,根据实现,每个元素只能存储一位。有没有办法利用这个来有效地清除整个事情?

固定长度变体

bitset具有set功能。 vector<bool>有类似的东西吗?

8 个答案:

答案 0 :(得分:19)

到目前为止,在答案中似乎有很多猜测但很少有事实,所以也许值得做一些测试。

#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 ++,结果只是 tad 不同:

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 ms差异不是真正可重复的。)

对于它的价值,尽管这部分测试用g ++显示为很多,但总体时间在1%之内(VC ++为4.944秒,4.915秒为克++)。

答案 1 :(得分:13)

尝试

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

看看这个链接: http://www.cplusplus.com/reference/vector/vector/assign/

或以下

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

答案 2 :(得分:9)

你运气不好。 std::vector<bool>是一个专门化,显然甚至不保证连续内存或随机访问迭代器(甚至转发?!),至少基于我对cppreference的读取 - 解码标准将是下一步。

所以编写实现特定的代码,祈祷并使用一些标准的归零技术,或者不使用该类型。我投票3。

接受的智慧是,这是一个错误,可能会被弃用。如果可能,请使用其他容器。绝对不要乱用内部胆量,或依靠其包装。检查std库mayhap中是否有动态位集,或者在std::vector<unsigned char>周围滚动自己的包装。

答案 3 :(得分:6)

使用为此目的提供的std::vector<bool>::assign方法。 如果某个实施特定于bool,那么assign很可能也会适当地实施。

答案 4 :(得分:6)

我最近遇到了这个性能问题。我没有尝试在网上寻找答案,但确实发现使用构造函数的赋值使用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>的专业化;只是非常了解位向量表示。

答案 5 :(得分:5)

如果您能够从vector<bool>切换到自定义位向量表示,那么您可以使用专为快速清除操作而设计的表示,并获得一些可能非常显着的加速(尽管不是没有权衡) )。

技巧是使用每位向量输入的整数和单个滚动阈值&#39;确定哪些条目实际评估为真的值。

然后,您可以通过增加单个阈值来清除位向量,而不会触及其余数据(直到阈值​​溢出)。

可以找到关于此问题以及一些示例代码的更完整的文章here

答案 6 :(得分:3)

似乎还没有提到一个不错的选择:

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

据说STL实施者已经选择了最有效的归零方法,因此我们甚至不需要知道可能采用哪种特定方法。这也适用于真实的向量(思考模板),而不仅仅是std::vector<bool>怪物。

循环中重复使用的缓冲区(例如,sieves,无论如何)可以有一个微不足道的附加优势,你可以简单地调整当前轮次所需的任何内容,而不是原始大小。

答案 7 :(得分:0)

作为std::vector<bool>的替代方法,签出boost::dynamic_bitsethttps://www.boost.org/doc/libs/1_72_0/libs/dynamic_bitset/dynamic_bitset.html)。您可以通过调用reset()成员函数将一个零(即,将每个元素设置为false)。

像在std::vector<int>上清除resetboost::dynamic_bitset一样,也可以编译为memset,而用{{1 }}。例如,请参见https://godbolt.org/z/aqSGCi