Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

const array vs static const array in a function

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.

like image 937
fogbit Avatar asked Oct 10 '11 13:10

fogbit


3 Answers

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.

like image 95
David Heffernan Avatar answered Oct 21 '22 11:10

David Heffernan


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.

like image 4
NPE Avatar answered Oct 21 '22 09:10

NPE


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.

like image 2
Mark B Avatar answered Oct 21 '22 11:10

Mark B