Reputation: 828
int a[100] = {};
int a[100];
memset(a, 0, sizeof(a));
int a[100];
fill(a, a + 100, 0);
What is the best way to zero a new array from the methods shown above and what is the difference between them?
Upvotes: 4
Views: 357
Reputation: 1902
Using Keith's sample code. The difference under GCC are as follows:
GCC 4.7.3: g++ -Wall -Wextra -std=c++0x -O3 -c array-fill.cpp
#include <algorithm>
#include <cstring>
int fref() {
int a[1024];
return a[512] - a[256]; }
int f1() {
int a[1024] = {};
return a[512] - a[256]; }
int f2() {
int a[1024];
std::memset(a, 0, sizeof(a));
return a[512] - a[256]; }
int f3() {
int a[1024];
std::fill(a, a + 100, 0);
return a[512] - a[256]; }
Disassemble
objdump -d array-fill.o | c++filt
00000000 <fref()>:
0: b8 00 10 00 00 mov $0x1000,%eax
5: e8 00 00 00 00 call a <fref()+0xa>
a: 29 c4 sub %eax,%esp
c: 8b 84 24 00 08 00 00 mov 0x800(%esp),%eax
13: 2b 84 24 00 04 00 00 sub 0x400(%esp),%eax
1a: 81 c4 00 10 00 00 add $0x1000,%esp
20: c3 ret
21: eb 0d jmp 30 <f1()>
00000030 <f1()>:
30: 31 c0 xor %eax,%eax
32: c3 ret
33: 8d b6 00 00 00 00 lea 0x0(%esi),%esi
39: 8d bc 27 00 00 00 00 lea 0x0(%edi,%eiz,1),%edi
00000040 <f2()>:
40: b8 00 10 00 00 mov $0x1000,%eax
45: e8 00 00 00 00 call 4a <f2()+0xa>
4a: 29 c4 sub %eax,%esp
4c: 31 c0 xor %eax,%eax
4e: 81 c4 00 10 00 00 add $0x1000,%esp
54: c3 ret
55: 8d 74 26 00 lea 0x0(%esi,%eiz,1),%esi
59: 8d bc 27 00 00 00 00 lea 0x0(%edi,%eiz,1),%edi
00000060 <f3()>:
60: b8 00 10 00 00 mov $0x1000,%eax
65: e8 00 00 00 00 call 6a <f3()+0xa>
6a: 29 c4 sub %eax,%esp
6c: 89 e0 mov %esp,%eax
6e: 8d 94 24 90 01 00 00 lea 0x190(%esp),%edx
75: c7 00 00 00 00 00 movl $0x0,(%eax)
7b: 83 c0 04 add $0x4,%eax
7e: 39 d0 cmp %edx,%eax
80: 75 f3 jne 75 <f3()+0x15>
82: 8b 84 24 00 08 00 00 mov 0x800(%esp),%eax
89: 2b 84 24 00 04 00 00 sub 0x400(%esp),%eax
90: 81 c4 00 10 00 00 add $0x1000,%esp
96: c3 ret
The C style initialization (f1
) certainly allowed optimization in this case!
Upvotes: 1
Reputation: 6834
Decided to investigate the performance question using VS2010, full optimization.
Interesting result:
1: 13105
2: 13044
3: 4546
No initialization case: 906.
So it looks highly like VS2010 uses memset
for case 1
, but that fill
is better optimized.
#include "stdafx.h"
#include <Windows.h>
#include <algorithm>
#include <iostream>
int fref()
{
int a[1024];
return a[512] - a[256];
}
int f1()
{
int a[1024] = {};
return a[512] - a[256];
}
int f2()
{
int a[1024];
memset(a, 0, sizeof(a));
return a[512] - a[256];
}
int f3()
{
int a[1024];
std::fill(a, a + 100, 0);
return a[512] - a[256];
}
typedef int (*Function)();
LONGLONG time(Function function)
{
const unsigned numLoops = 50000;
LARGE_INTEGER start;
QueryPerformanceCounter(&start);
for(unsigned j = 1; j != numLoops; ++j)
function();
LARGE_INTEGER end;
QueryPerformanceCounter(&end);
return end.QuadPart-start.QuadPart;
}
Function tests[]=
{
&fref, &f1, &f2, &f3
};
const unsigned numTests = sizeof(tests)/sizeof(tests[0]);
LONGLONG results[numTests] = {};
int _tmain(int argc, _TCHAR* argv[])
{
for(unsigned i = 0; i != numTests; ++i)
{
results[i] = time(tests[i]);
}
for(unsigned i = 0; i != numTests; ++i)
std::cout << results[i] << std::endl;
getchar();
return 0;
}
Upvotes: 2
Reputation: 1795
1: The best. It sets all the values to their default value which for most is 0.
2: This is dangerous, it copies the pattern 0 through the whole array. For example if the array is of floats, there is no guarantee that it is represented as zeros. Also memset copies byte wise NOT word wise which can cause all sorts of issues if you pass it something other than zero. For example memset(a, 1, ...)
will cause it to be filled with 16843009
. Memset should not be used unless you are using C-strings.
3: Legal, and legible. Easy to extend to non-zero values while (1) will not. Although more verbose.
Upvotes: 4