Когда статические переменные функционального уровня выделяются / инициализируются?



Я вполне уверен, что глобально объявленные переменные выделяются (и инициализируются, если это применимо) во время запуска программы.



int globalgarbage;
unsigned int anumber = 42;


но как насчет статических, определенных в функции?



void doSomething()
{
static bool globalish = true;
// ...
}


когда есть место для globalish выделено? Я предполагаю, когда начнется программа. Но тогда он тоже инициализируется? Или он инициализируется, когда doSomething() - Это первая называется?

513   7  

7 ответов:

мне было любопытно об этом, поэтому я написал тестовую программу и скомпилировать его с G++ версии 4.1.2.

include <iostream>
#include <string>

using namespace std;

class test
{
public:
        test(const char *name)
                : _name(name)
        {
                cout << _name << " created" << endl;
        }

        ~test()
        {
                cout << _name << " destroyed" << endl;
        }

        string _name;
};

test t("global variable");

void f()
{
        static test t("static variable");

        test t2("Local variable");

        cout << "Function executed" << endl;
}


int main()
{
        test t("local to main");

        cout << "Program start" << endl;

        f();

        cout << "Program end" << endl;
        return 0;
}

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

global variable created
local to main created
Program start
static variable created
Local variable created
Function executed
Local variable destroyed
Program end
local to main destroyed
static variable destroyed
global variable destroyed

некоторые соответствующие глаголы из стандарта C++:

3.6.2 инициализация нелокальных объектов [basic.начать.init]

1

хранилище для объектов со статическим хранилищем продолжительность (основные.НТЦ.статика) должны быть инициализированы нулем ( dcl.init) прежде чем произойдет любая другая инициализация. Объекты Типы стручков (основные.типы) статическое хранение продолжительность инициализируется с помощью постоянных выражений ( expr.константный) будет инициализируется перед любой динамической инициализацией. Объекты области пространства имен со статической длительностью хранения, определенной в такой же блок перевода и динамически инициализированный будет инициализируются в порядке их определения в единица перевода. [Примечание: dcl.в этом.аггр описывает порядок, в котором агрегатные элементы инициализированный. Этот инициализация локальных статических объектов описана в stmt.dcl. ]

[больше текста ниже добавление больше свобод для авторов компилятора]

6.7 заявление о декларации [stmt.РСН]

...

4

нулевой инициализации ( dcl.init) всех локальных объектов с статическая длительность хранения (основные.НТЦ.статика) является выполненный ранее любая другая инициализация имеет место. Локальный объект Тип стручка (основные.типы) со статической продолжительностью хранения инициализируется константой-выражения инициализируются до его блок вводится первым. Реализация разрешается выполнять ранняя инициализация других локальных объектов со статическим хранилищем срок на тех же условиях, что реализация разрешено статически инициализировать объект со статическим хранилищем продолжительность в области пространства имен (основные.начать.init). В противном случае такие объект инициализируется при первом прохождении элемента управления через его объявление; такой объект считается инициализированным на завершения его инициализации. Если инициализация завершается исключение, инициализация не завершена, поэтому он будет повторите попытку при следующем вводе элемента управления в объявление. Если элемент управления повторно вводит объявление (рекурсивно) во время объекта инициализировано, поведение не определено. [пример:

      int foo(int i)
      {
          static int s = foo(2*i);  // recursive call - undefined
          return i+1;
      }

--пример]

5

деструктор для локального объекта со статической длительностью хранения будет выполняется тогда и только тогда, когда переменная была построена. [Примечание:основные.начать.срок описывает порядок, в котором местные объекты со статической длительностью хранения уничтожаются. ]

память для всех статических переменных выделяется при загрузке программы. Но локальные статические переменные создаются и инициализируются при первом их использовании, а не при запуске программы. Есть некоторые хорошие чтения об этом, и статика в целом,здесь. В общем я думаю, что некоторые из этих вопросов зависит от реализации, особенно, если вы хотите знать, где в памяти этот материал будет размещен.

компилятор выделит статические переменные, определенные в функции foo при загрузке программы, однако компилятор также добавит некоторые дополнительные инструкции (машинный код) к вашей функции foo Так что при первом вызове этот дополнительный код инициализирует статическую переменную (например, вызов конструктора, если применимо).

@Adam: это закулисная инъекция кода компилятором является причиной результата, который вы видели.

Я пытаюсь снова проверить код Адам Пирс и добавил еще два случая: статическая переменная в классе и тип POD. Мой компилятор-g++ 4.8.1, в ОС Windows(MinGW-32). Результат-статическая переменная в классе обрабатывается одинаково с глобальной переменной. Его конструктор будет вызван перед вводом основной функции.

  • заключение (для g++, среда Windows):

    1. глобальная переменная и статический член класса: конструктор вызывается перед вводом главная функции (1).
    2. локальная статическая переменная: конструктор вызывается только тогда, когда выполнение достигает своего объявления в первый раз.
    3. если локальная статическая переменная типа POD, то он также инициализируется перед вводом главная функции (1). Пример для типа стручка:статический int количество = 10;

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

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

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

по этой причине вам гарантируется, что статическая переменная будет инициализирована до 0 (если вы не укажете что-то еще), а не неопределенное значение.

есть некоторые другие аспекты инициализация вы можете воспользоваться преимуществами -- например, общие сегменты позволяют различным экземплярам вашего исполняемого файла работать одновременно для доступа к одним и тем же статическим переменным.

в C++ (в глобальном масштабе) статические объекты имеют свои конструкторы, вызываемые как часть запуска программы под управлением библиотеки времени выполнения C. В Visual C++ по крайней мере порядок, в котором инициализируются объекты, может управляться init_seg pragma.

или он инициализируется при первом вызове doSomething ()?

Да, это так. Это, среди прочего, позволяет инициализировать глобально доступные структуры данных, когда это необходимо, например, внутри блоков try/catch. Например, вместо

int foo = init(); // bad if init() throws something

int main() {
  try {
    ...
  }
  catch(...){
    ...
  }
}

можно писать

int& foo() {
  static int myfoo = init();
  return myfoo;
}

и использовать его внутри блока try / catch. При первом вызове переменная будет инициализирована. Затем, при первом и следующем вызовах, его значение будет возвращено (by ссылка.)

Comments

    Ничего не найдено.