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

const array vs static const array in a function

本文关键字:数组 Const 静态 函数      更新时间:2023-10-16

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

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以同样的方式工作,没有必要写"static"关键字。

所以我想问的是标准是否对情况有规定#1 ,如果有,具体是什么?我应该如何定义这种类型的数组,以确保它将被分配/初始化只有一次?

谢谢。

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

您的示例非常简单,因为该数组涉及纯旧数据(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次

我的编译器(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

我不知道其他编译器是否以同样的方式运行

以最符合逻辑和最清晰的方式声明和定义它,只有当分析显示它是一个瓶颈时,我才会建议更改代码。

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