将std :: vector <int>的每个值重置为0的最快方法


Answers:


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

48
查看汇编输出,实际上gcc将此循环展开为使用m​​mx寄存器一次转储16个字节,直到它接近结尾为止。我会说那非常快。memset版本跳到了memset,我想它的速度差不多。我会用你的方法。
2012年

但是,跳转到memset是一条指令,因此使用它会导致二进制大小更小。
亚历山大·希申科

2
这并非OP所要求的,而是简单地将向量重新分配给相同大小的新向量(v = std::vector<int>(vec_size,0))似乎比fill我的机器上快一点
Yibo Yang

1
这是最惯用的方式,比使用更惯用assign
alfC

1
将其分配给新向量不会进行堆分配吗?然后丢弃现有向量的分配?我看得出来,比memset的等慢
康拉德·琼斯

150

一如既往,当您询问最快的速度时:测量!使用上述方法(在使用Clang的Mac上):

Method      |  executable size  |  Time Taken (in sec) |
            |  -O0    |  -O3    |  -O0      |  -O3     |  
------------|---------|---------|-----------|----------|
1. memset   | 17 kB   | 8.6 kB  | 0.125     | 0.124    |
2. fill     | 19 kB   | 8.6 kB  | 13.4      | 0.124    |
3. manual   | 19 kB   | 8.6 kB  | 14.5      | 0.124    |
4. assign   | 24 kB   | 9.0 kB  | 1.9       | 0.591    |

在10000个整数的向量上使用100000次迭代。

编辑:如果振振有词量变到质变这一数字变化所产生的时候,你可以有一些信心(还不如检查最终汇编代码),人工基准尚未完全优化掉。当然,最好在实际条件下降低性能。 结束编辑

作为参考,使用的代码:

#include <vector>

#define TEST_METHOD 1
const size_t TEST_ITERATIONS = 100000;
const size_t TEST_ARRAY_SIZE = 10000;

int main(int argc, char** argv) {

   std::vector<int> v(TEST_ARRAY_SIZE, 0);

   for(size_t i = 0; i < TEST_ITERATIONS; ++i) {
   #if TEST_METHOD == 1 
      memset(&v[0], 0, v.size() * sizeof v[0]);
   #elif TEST_METHOD == 2
      std::fill(v.begin(), v.end(), 0);
   #elif TEST_METHOD == 3
      for (std::vector<int>::iterator it=v.begin(), end=v.end(); it!=end; ++it) {
         *it = 0;
      }
   #elif TEST_METHOD == 4
      v.assign(v.size(),0);
   #endif
   }

   return EXIT_SUCCESS;
}

结论:使用std::fill(因为正如其他人所说的是最惯用的)!


3
+1。这个特定的基准测试不是确定性的,但是这一点是绝对正确的,您应该编写替代方案的性能测试,因为它们将被实际使用。如果没有性能差异,则使用最简单的来源。
史蒂夫·杰索普

3
“ ...没有结论性……” IMO这种不确定性本身已经是进行基准测试的一个好点,对于OP所要求的那种情况,Optimizer通常已经做好了很多工作。我会修改您的最后一句话为“如果没有明显的性能差异……”
Fabio Fracassi 2012年

4
更新使用Nonius进行基准测试:clang3.6-libc ++-c ++ 1y-O3gcc4.9-c ++ 1y-O3gcc5-c ++ 1y-O3 - TL; DRassign速度较慢,但​​容量较小在libc++。CODE coliru / paste
sehe 2015年

2
另外,哇,如果您关心速度而不进行优化(如果您以“调试”模式进行部署,这可能是合理的,有些团队会这样做),那么fill看起来就很糟糕。这是两个数量级在本次测试速度较慢。
凯尔·斯特兰德

5
@KyleStrand:并不是说填充很糟糕,它是模板,并且代码是在翻译单元内用-O0生成的。使用memset时,将使用以-O3编译的libc代码(即使使用-O0编译代码)。如果您关心调试的速度并且使用模板,则必须在单独的文件中使用显式模板实例化,并使用-O3进行编译
Tic Tic

25

如何在assign成员函数?

some_vector.assign(some_vector.size(), 0);

2
OP希望重设现有值,但是想要调整大小重设值时,您的答案会更好。谢谢!

15

如果它只是整数的向量,我首先尝试:

memset(&my_vector[0], 0, my_vector.size() * sizeof my_vector[0]);

它不是C ++,所以我确定有人会提供正确的方法。:)


3
由于标准(2003 TC1)保证std :: vector在内存中是连续的,因此应该没问题。如果您的c ++库不符合2003 TC1,则不要使用它。
马里奥(Mario)2012年

2
@马里奥:除非那是真的,并且假定是众所周知的,否则我不会发布此内容。:)但是,谢谢。
2012年

1
我检查了组装。该::std::fill方法扩展到相当快的方法,尽管在代码繁华方面有点,因为它们都是内联的。我仍然会用它,因为它读起来要好得多。
2012年

4
您最好添加检查vector是否为空,在这种情况下什么也不做。为空向量计算&buf [0]可以在STL代码中生成断言。
谢尔盖

4

尝试

std::fill

并且

std::size siz = vec.size();
//no memory allocating
vec.resize(0);
vec.resize(siz, 0);

调整大小非常好
Nick

3

我有一个相同的问题,但很短vector<bool>(afaik,该标准允许在内部以不同于连续的布尔元素数组的方式实现它)。因此,我重复了法比奥·弗拉卡西(Fabio Fracassi)稍加修改的测试。结果如下(时间,以秒为单位):

            -O0       -O3
         --------  --------
memset     0.666     1.045
fill      19.357     1.066
iterator  67.368     1.043
assign    17.975     0.530
for i     22.610     1.004

因此,显然对于这些大小,vector<bool>::assign()速度更快。用于测试的代码:

#include <vector>
#include <cstring>
#include <cstdlib>

#define TEST_METHOD 5
const size_t TEST_ITERATIONS = 34359738;
const size_t TEST_ARRAY_SIZE = 200;

using namespace std;

int main(int argc, char** argv) {

    std::vector<int> v(TEST_ARRAY_SIZE, 0);

    for(size_t i = 0; i < TEST_ITERATIONS; ++i) {
#if TEST_METHOD == 1
        memset(&v[0], false, v.size() * sizeof v[0]);
#elif TEST_METHOD == 2
        std::fill(v.begin(), v.end(), false);
   #elif TEST_METHOD == 3
        for (std::vector<int>::iterator it=v.begin(), end=v.end(); it!=end; ++it) {
            *it = 0;
        }
   #elif TEST_METHOD == 4
      v.assign(v.size(),false);
   #elif TEST_METHOD == 5
      for (size_t i = 0; i < TEST_ARRAY_SIZE; i++) {
          v[i] = false;
      }
#endif
    }

    return EXIT_SUCCESS;
}

我在Ubuntu 17.10上使用了GCC 7.2.0编译器。用于编译的命令行:

g++ -std=c++11 -O0 main.cpp
g++ -std=c++11 -O3 main.cpp
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.