const数组与函数中的静态const数组

时间:2011-10-10 13:13:16

标签: c++ arrays static const

例如,有一个功能在做某事。我应该如何在函数内声明和定义一个数组,我只想分配/初始化一次?

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
}

据我所知,#1“my_array”将在数据段中分配,并在第一次“somefunction”调用时初始化一次。但是我的一位同事假设案例#2以相同的方式工作,并且不需要编写“静态”关键字。

所以我想问一下这个标准是关于案例#1& #2,如果确实如此,究竟是什么?我应该如何定义这种类型的数组,以便它只被分配/初始化一次?

谢谢。

4 个答案:

答案 0 :(得分:5)

编译器将为这两个选项生成相同的代码。

由于数组涉及普通旧数据(POD),因此您的示例非常简单。该标准表示每次运行somefunction时都会初始化选项1,但是第一次运行somefunction时将初始化选项2。但是,只要结果与标准中指定的结果(即所谓的 as-if 规则)无法区分,就允许实现偏离。

在这种情况下,编译器将数组写入可执行文件的只读内存中,并且在运行时根本没有初始化。他们可以用POD类型做到这一点。

如果你有一个需要运行时实例化的对象,那么事情会有所不同。考虑以下程序的行为:

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;
}

MyObject的构造函数运行3次。

答案 1 :(得分:4)

我的编译器(gcc 4.4.3)在这两种情况下生成相同的代码。

源代码:

void f()
{
  static const my_array[4] = {1,2,3,4}; // #1
}

void g()
{
  const my_array[4] = {1,2,3,4}; // #2
}

生成的程序集:

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

我不知道其他编译器的行为方式是否相同。

答案 2 :(得分:2)

以最合乎逻辑且最清晰的方式声明并定义它,并且只有在分析显示它是瓶颈的情况下才会建议更改代码。

在这种情况下,一些编译器可能会生成相同的代码。由于初始化语义略有不同,其他人可能会生成不同的代码(例如,在某些情况下,g ++通过互斥锁保护静态的初始化)。

事实上,确定您的特定编译器的唯一方法是查看反汇编。

答案 3 :(得分:0)

在函数内部,您可能希望避免使用static,因为这也只能初始化声明一次。所以这种类型的声明(用于顺序搜索结构)可能会导致细微的错误(迭代器mapi只会被初始化一次):

static struct {
    int a;
    char c;
} const someConstantMap[] = { { 1, 'a' }, { 2, 'b'}, { 0 } },
                    *mapi = someConstantMap;

而省略static将为您提供const数组和迭代器,如您所料。