如何用1个真正大的数组快速初始化

时间:2013-05-05 14:21:38

标签: c++ arrays performance

我有很多阵容:

int* arr = new int[BIGNUMBER];

如何快速实现1号码。通常我会做

for(int i = 0; i < BIGNUMBER; i++)
    arr[i] = 1

但我认为这需要很长时间。

我可以使用memcpy或类似的吗?

8 个答案:

答案 0 :(得分:13)

您可以尝试使用标准函数std::uninitialized_fill_n

#include <memory>

// ...

std::uninitialized_fill_n(arr, BIGNUMBER, 1);

在任何情况下,当涉及到性能时,规则是始终进行测量以支持您的假设 - 特别是如果您要放弃一个清晰,简单的设计来接受更复杂的设计,因为所谓的性能提升

修改

请注意 - as Benjamin Lindley mentioned in the comments - 对于琐碎的类型std::uninitialized_fill_n并没有比更明显的std::fill_n带来任何优势。对于非平凡类型存在优势,因为std::uninitialized_fill将允许您分配内存区域,然后在适当位置构造对象。

但是,对于未初始化的内存区域,不应该陷入调用std::uninitialized_fill_n的陷阱。例如,以下内容将给出未定义的行为:

my_object* v = new my_object[BIGNUMBER];
std::uninitialized_fill_n(my_object, BIGNUMBER, my_object(42)); // UB!

答案 1 :(得分:4)

动态数组的替代是std::vector<int>,其构造函数接受每个元素的初始值:

std::vector<int> v(BIGNUMBER, 1); // 'BIGNUMBER' elements, all with value 1.

如前所述,需要衡量绩效。这种方法提供了额外的好处,即内存将自动释放。

答案 2 :(得分:2)

Andy Prowl的std::uninitialized_fill_n()解决方案的一些可能替代方案,仅供后人使用:

  • 如果你很幸运,你的价值由所有相同的字节组成,memset就可以了。
  • 某些实现提供了16位版本memsetw,但并非随处可见。
  • GCC的Designated Initializers扩展名可填写范围。
  • 我使用过一些ARM系统,这些系统的库具有加速的CPU和DMA变体字填充,在汇编中手动编码 - 你可能会看看你的平台是否提供任何这些,如果你不是'非常担心便携性。
  • 根据您的处理器,即使查看SIMD内在函数周围的循环也可能会提升;一些SIMD单元具有加载/存储管道,这些管道针对像这样移动数据进行了优化。另一方面,您可能会因在寄存器类型之间移动而受到严厉处罚。

最后但并非最不重要的是,回应一些评论者:你应该测试一下。编译器往往非常擅长识别和优化这样的模式 - 你可能只是简单地使用简单循环或uninitialized_fill_n之外的任何东西来处理可移植性或可读性。

您可能对之前的问题感兴趣:

答案 3 :(得分:1)

在启用了优化的Linux / x86 gcc下,您的代码将编译为以下内容:

rax = arr
rdi = BIGNUMBER

400690: c7 04 90 01 00 00 00    movl   $0x1,(%rax,%rdx,4)

立即将int(1)移至rax + rdx

400697: 48 83 c2 01             add    $0x1,%rdx

增量寄存器rdx

40069b: 48 39 fa                cmp    %rdi,%rdx

Cmp rdi to rdx

40069e: 75 f0                   jne    400690 <main+0xa0>

如果已达到BIGNUMBER,请跳回去开始。

我的机器上每GB大约需要1秒钟,但我敢打赌的大多数是在物理内存中进行分页以支持未初始化的分配。

答案 4 :(得分:1)

只需将循环展开8或16次即可。像memcpy这样的函数速度很快,但为方便起见,它们确实存在,而不是比你可能编写的任何东西更快:

for (i = 0; i < BIGNUMBER-8; i += 8){
  a[i+0] = 1; // this gets rid of the test against BIGNUMBER, and the increment, on 7 out of 8 items.
  a[i+1] = 1; // the compiler should be able to see that a[i] is being calculated repeatedly here
  ...
  a[i+7] = 1;
}
for (; i < BIGNUMBER; i++) a[i] = 1;

编译器可能能够为你展开循环,但为什么要冒这个机会呢?

答案 5 :(得分:-2)

使用memset或memcpy

memset(arr, 0, BIGNUMER); 

答案 6 :(得分:-2)

尝试使用memset?

memset(arr, 1, BIGNUMBER);

http://www.cplusplus.com/reference/cstring/memset/

答案 7 :(得分:-2)

memset(arr,1,sizeof(int)* BIGNUMBER);