Статическая инициализация объекта

#c

#c

Вопрос:

У меня есть глобальный объект, который объявляется перед функцией main, и статический объект внутри main.

  • Какой из них использует (или выполняет оба?) статическую инициализацию?
  • Я слышал, что A obj1 это также называется статическим; почему это так?

 class A { ... };

A obj1;

int main()
{
    static A obj2;
}
  

Комментарии:

1. Это похоже на домашнее задание, пожалуйста, используйте соответствующий тег.

2. почему это выглядит как домашнее задание?

3. Потому что пример выглядит как пример из учебника.

Ответ №1:

obj1 имеет статическое хранилище. Он будет инициализирован при запуске программы.

obj2 также имеет статическое хранилище, потому что вы так сказали. Он будет инициализирован при main() первом выполнении.

Комментарии:

1. для записи: obj1 имеет статическое хранилище, поскольку он является глобальным / членом пространства имен (не связан с функцией (областью действия) или классом (экземпляром))

2. не все ли статические объекты хранилища инициализируются нулем при запуске программы?

3. @user974191: Нет, наиболее очевидным контрпримером будут строковые литералы "such as this" .

4. @MSalters: sec (8.5/6) Every object of static storage duration shall be zero-initialized at program startup before any other initialization takes place.

5. @MSalters: Это совсем не очевидно. Вы хотите сказать, что static int x = 3; это не заканчивается значением 3 , потому что оно инициализируется нулем в качестве первого шага?

Ответ №2:

Мое первое сомнение заключается в том, насколько точен вопрос. Если статическая инициализация используется с техническим значением в стандарте, она представляет собой инициализацию с нулевым значением и инициализацию типа POD с постоянными выражениями для объектов с длительностью хранения, по сравнению с динамической инициализацией, где инициализация объекта со статической продолжительностью хранения инициализируется как-то иначе.

Для наглядного примера:

 // at namespace level
int f();
int a;         // 1 static: zero initialization
int b = 10;    // 2 static: initialization from constant expression
int c = f();   // 3 static (zero initialization)
               // 5 followed by dynamic (result of call to f())
int d = 20;    // 4 static: initialization
int f() { return d; }
int main() {}
  

Число указывает порядок выполнения каждого шага инициализации. Причина, по которой компилятор рассматривает как статическую, так и динамическую инициализацию, заключается в том, что он устанавливает порядок выполнения инициализации. статическая инициализация выполняется перед динамической инициализацией, и все статически инициализированные объекты гарантированно получат свое значение до начала любой динамической инициализации. То есть стандарт гарантирует, что даже если d появляется после c в предыдущей программе, значение c гарантированно равно 20 .

Для объектов, требующих динамической инициализации, они (концептуально) инициализируются нулем во время статической инициализации, поэтому в течение срока службы c сначала устанавливается значение 0, а затем сбрасывается f() (или 20 в этой программе). Концептуально это связано с тем фактом, что если компилятор может вывести конечное значение, которое получит переменная, он может оптимизировать динамическую инициализацию и просто выполнить простую статическую инициализацию с этим конечным значением (в приведенном выше коде компилятор может обнаружить, что c оно будет динамически инициализироваться до 20, ирешите преобразовать его в статическую инициализацию, как int c = 20; в соответствующей реализации. В этом случае шаги 3 и 5 в приведенном выше коде будут объединены в один шаг 3.

В случае локальной переменной со статической продолжительностью хранения стандарт не использует термины статическая/динамическая инициализация, но описания требуют такого же поведения от программы. Локальные переменные со статической длительностью инициализируются нулем или POD инициализируются с помощью постоянных выражений, когда (или до) блок вводится в первый раз (как при статической инициализации), в то время как для остальных инициализаций выполняются при первом переходе управления через его объявление.

Ответ №3:

Сосредоточив внимание только на C , вам также необходимо рассмотреть инициализацию статических членов. Это касается статических членов класса. Например, когда у вас есть:

 class A {
  // declaration of i as a static member of class A
  static int i;
};

// initialization of static member outside class A
int A::i = 42;
  

Комментарии:

1. Нет, это совсем не так. То, что вы i являетесь членом класса, не имеет никакого отношения к его статическому поведению при инициализации, и оно не сильно отличается от случая OP.

2. Я не думаю, что есть что-то неправильное в указании на то, что ключевое static слово применяется к членам класса в C или что эквивалент не существует для структур C. Это вопрос терминологии, поэтому, если нужно провести обзор области значения «статического», хорошо бы охватить все основы. Статические члены класса, статические методы класса и т. Д. 0,5 за упоминание об этом и 0,5 за упоминание Дугласа Адамса.

3. @jHackTheRipper: Вопрос не в названии. Обратите внимание, что этот ответ полностью изменился с момента моего первоначального комментария. Сейчас это не так уж плохо, но по-прежнему не отвечает на вопрос (который вообще не касается членов класса).

4. @HostileFork: И я не понимаю, какое отношение C имеет к чему-либо, но я полагаю, что если вы дадите половину голосов только за то, что написали «42», тогда вы проголосуете за что угодно!

5. @HostileFork: В этом нет ничего разговорного, и это не расплывчатый вопрос: вопрос очень четко сформулирован (Дэвиду удалось его понять), и этот ответ не имеет к нему никакого отношения . И текущая оценка вопроса или ответа не должна иметь абсолютно никакого отношения к тому, какой голос вы отдаете. Кроме того, причина, по которой у меня 37.6k, заключается в том, что мне нечего делать, кроме как вносить конструктивный вклад в переполнение стека

Ответ №4:

Обе эти переменные являются статическими:

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

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

Скотт Мейерс в своей книге «Эффективный C » рекомендует обращаться к локальным статическим переменным через функции, а не использовать нелокальные статические переменные. Это позволяет избежать так называемой проблемы со статическим порядком инициализации, когда одна переменная может ссылаться на другую, которая, возможно, еще не была инициализирована из-за произвольного порядка, в котором происходит инициализация.

Комментарии:

1. 1 «Фиаско порядка статической инициализации» parashift.com/c -faq-lite/ctors.html#faq-10.14