For example there is a function doing something. How should i declare and define an array inside the function i'd like to be allocated/initialized only once?
void someclass::somefunction(/*parameters here*/)
{
static const my_array[4] = {1,2,3,4}; // #1
/*or just*/
const my_array[4] = {1,2,3,4}; // #2
}
As far as i know in the case #1 "my_array" will be allocated in data segment and initialized once at the first time of "somefunction" calling. But a colleague of mine made an supposition that the case #2 works in the same manner and there is no need to write "static" key-word.
So i'd like to ask does the standart say something about cases #1 & #2 and, if it does, what exactly? How should i define such type of arrays to be sured that it will be allocated/initialized only once?
Thank you.
The compiler will produce identical code for these two options.
Your example is quite trivial since the array involves plain-old-data (POD). The standard says that option 1 will be initialized each time somefunction
is run, but option 2 will be initialized the first time somefunction
is run. However, implementations are allowed to deviate from that so long as the result is indistinguishable to that specified in the standard, the so-called as-if rule.
In this case compilers write the arrays into read-only memory of the executable and there is no initialization at all at runtime. They can do this with POD types.
If you had an object that required runtime instantiation then things would be different. Consider the behaviour of the following program:
class MyObject
{
public:
MyObject() {}
};
void f()
{
const MyObject arr1[1] = { MyObject() };
static const MyObject arr2[1] = { MyObject() };
}
int main(int argc, char* argv[])
{
f();
f();
return 0;
}
The constructor for MyObject
runs 3 times.
My compiler (gcc 4.4.3
) generates identical code in these two cases.
Source code:
void f()
{
static const my_array[4] = {1,2,3,4}; // #1
}
void g()
{
const my_array[4] = {1,2,3,4}; // #2
}
The resulting assembly:
f:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
movq %rsp, %rbp
.cfi_offset 6, -16
.cfi_def_cfa_register 6
leave
ret
.cfi_endproc
g:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
movq %rsp, %rbp
.cfi_offset 6, -16
.cfi_def_cfa_register 6
leave
ret
.cfi_endproc
.section .rodata
.align 16
.type my_array.1594, @object
.size my_array.1594, 16
my_array.1594:
.long 1
.long 2
.long 3
.long 4
.align 16
.type my_array.1591, @object
.size my_array.1591, 16
my_array.1591:
.long 1
.long 2
.long 3
.long 4
I don't know whether other compilers behave in the same manner.
Declare and define it the most logical and clear way, and only if profiling shows it to be a bottleneck would I suggest changing the code.
In this case some compilers may very well generate the same code. Others may generate different code due to the slightly different initialization semantics (for example in some cases g++ protects initialization of statics with a mutex lock).
In fact the only way to know for sure for your particular compiler is to look at the disassembly.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With