Время создания переменной

204
06 апреля 2017, 20:41

Например, есть искусственный пример: ...

int main() {
    /*
        некоторый код
    */
    ...{
        static int someVal = 42;
    }
}

Когда произойдет создание переменной? Во время запуска программы или когда доберемся до нужной инструкции?

Answer 1

Вопрос не имеет однозначного ответа, ибо ответ на него в общем случае критически зависит от типа объекта. В вашем конкретном примере с типом int - объект всегда создается строго во время запуска программы.

А в общем случае это зависит от того, что вы называете "созданием".

У объектов в С++ есть "период хранения" (storage duration) и "время жизни" (lifetime).

  • Период хранения - это период выделения-освобождения "сырой" памяти, занимаемой объектом.

    Период хранения любых статических объектов - это всегда безусловно все время выполнения программы.

  • Время жизни - это период между [нетривиальной] инициализацией и [нетривиальной] деструкцией объекта в этой сырой памяти. Время жизни всегда вложено в период хранения. Время жизни зависит от свойств объекта.

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

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

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

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

В вашем случае вы имеет дело с статическим объектом типа int. Период хранения такого объекта - все время выполнения программы. И так как это не-класс тип, время жизни этого объекта - все время выполнения программы. Также язык гарантирует вам, что инициализация этого объекта делается статически - не во время первого прохода выполнения по объявлению этого объекта, а сразу на старте программы.

Например, вот такой код гарантированно выведет 42

// Продолжительность хранения `i` уже началась
// Время жизни `i` уже началось
// `i` уже проинициализировано значением 42
int main()
{
goto skip;    
  static int i = 42; // Статическая инициализация
skip:
  std::cout << i << std::endl;
}

А вот такой гарантированно выведет 0

// Продолжительность хранения `i` уже началась
// Время жизни `i` уже началось
// `i` уже проинициализировано значением 0
int main()
{
goto skip;    
  static int i = std::rand(); // Динамическая инициализация
skip:
  std::cout << i << std::endl;
}

Если вы замените int на std::string, то период хранения такого объекта - все равно все время выполнения программы. А вот время жизни этого объекта начнется тогда, когда выполнение в первый раз пройдет по его объявлению (если такой момент вообще наступит).

Например, вот такой код

// Продолжительность хранения `s` уже началась
// Время жизни `s` еще не началось
// Однако все члены `s` уже проинициализированы нулями
int main()
{
goto skip;    
  static std::string s = "Hello World!"; // Динамическая инициализация и начало жизни
skip:
  std::cout << s << std::endl;
}

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

Answer 2

При первом выполнении кода.

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

struct Test
{
    Test(int x) { cout << x << endl; }
};

int main()
{
    for(int i = 0; i < 10; ++i)
    {
        cout << i << endl;
        static Test t = 42;
    }
}

Получим

0
42
1
2
3
4
5
6
7
8
9

А что такое создание переменной, как не вызов конструктора? :)

Answer 3

Подозреваю, что зависит от дальнейшего кода и/или настроек компилятора. Такой пример

static int someVal = 42;
printf ("0x%X", someVal);

Дает на выходе такой код:

.text:0040101E                 push    42
.text:00401020                 push    offset Format   ; "0x%X"
.text:00401025                 call    esi ; __imp__printf

То есть переменной как таковой и нет, компилятор соптимизировал ее в константу. А вот такой код:

printf ("0x%X", someVal);
someVal++;
printf ("0x%X", someVal);

Приводит к созданию глобальной переменной, инициализированной во время компиляции.

READ ALSO
Вектор с шаблонируемым классом

Вектор с шаблонируемым классом

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

264
Можно ли в кострукторе класса проверить некое условие и сразу запустить деструктор, если условие не удовлетворяет?

Можно ли в кострукторе класса проверить некое условие и сразу запустить деструктор, если условие не удовлетворяет?

Можно ли в конструкторе класса проверить некое условие и сразу запустить деструктор, если условие не удовлетворяется? Или же придется бросать...

231
Вопрос по очереди

Вопрос по очереди

Нужно разделить очередь на две, в одну значения большие или равные среднему,во вторую меньшие,при этом не создавая новую(задание такое)Как...

223