константный массив против статического константного массива в функции - PullRequest
10 голосов
/ 10 октября 2011

Например, есть функция, которая что-то делает.Как мне объявить и определить массив внутри функции, которую я хотел бы распределить / инициализировать только один раз?

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 ]

5 голосов
/ 10 октября 2011

Компилятор выдаст идентичный код для этих двух параметров.

Ваш пример довольно тривиален, так как массив включает в себя простые старые данные (POD).Стандарт гласит, что опция 1 будет инициализироваться при каждом запуске somefunction, но опция 2 будет инициализироваться при первом запуске somefunction.Тем не менее, реализациям разрешается отклоняться от этого, если результат неотличим от указанного в стандарте, так называемое как если бы правило.

В этом случае компиляторы пишутМассивы в постоянную память исполняемого файла, и во время выполнения инициализация вообще отсутствует.Они могут делать это с типами 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 раза.

4 голосов
/ 10 октября 2011

Мой компилятор (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 голосов
/ 10 октября 2011

Объявите и определите его наиболее логичным и понятным способом, и только если профилирование покажет, что это узкое место, я бы предложил изменить код.

В этом случае некоторые компиляторы вполне могут сгенерировать один и тот же код.Другие могут генерировать другой код из-за немного другой семантики инициализации (например, в некоторых случаях g ++ защищает инициализацию статики с помощью блокировки мьютекса).

Фактически, единственный способ узнать наверняка для вашего конкретного компилятора этопосмотрите на разборку.

0 голосов
/ 29 октября 2013

Внутри функции вы можете избежать использования static, поскольку это также приводит к инициализации объявления только один раз. Поэтому этот тип объявления (используемый для последовательного поиска структур) может привести к незначительным ошибкам (итератор mapi будет инициализирован только один раз):

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

, тогда как пропуск static даст вам массив const и итератор, как и следовало ожидать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...