2016-06-10 2 views
4

В самом деле, эта проблема происходит от слов в стандартном проекте N4582:Как понять, что реализации разрешено рассматривать динамическую инициализацию нелокальной переменной как статическую инициализацию в некоторых случаях?

[basic.start.static/3] Реализация разрешено выполнять инициализацию переменной со статическим или хранения нити длительностью как статическая инициализация, даже если такая инициализация не требуется статически, при условии, что

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

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

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

+0

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

+0

Это только моя интерпретация, но я сомневаюсь, что нулевая инициализация перед «вызовом» конструктора требуется - целью конструктора, помимо прочего, является инициализация памяти, занимаемой объектом. Правила статической и динамической инициализации влияют на порядок построения отдельных объектов. Однако правила являются рекурсивными, поскольку объекты имеют базы и содержат элементы, которые инициализируются перед вызовом конструктора. Член класса, не являющийся классом (например, 'int'), может быть нулевым инициализирован в этом процессе. – Peter

+0

@RSahu Спасибо за ваш ответ, но я хочу сказать, почему конструктор определенно будет называться? Вызов конструктора - это поведение в динамической инициализации, но, как говорят эти слова в стандарте, динамическая инициализация разрешена как статическая инициализация. – xskxzr

ответ

1

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

Примеры:

namespace A { 
    // statically zero-initialized 
    int a; 
    char buf1[10]; 

    // non-zero initialized 
    int b = 1; 
    char date_format[] = "YYYY-MM-DD"; 
} 

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

Примеры:

namespace B { 
    int a = strlen(A::date_format); (1) 
    int b = ++a;      (2) 

    time_t t = time();    (3) 

    struct C { 
     int i; 

     C() : i(123) {} 
    }; 

    C c;        (4) 

    double s = std::sqrt(2);   (5) 
} 

Теперь, стандарт C++ позволяет компилятору выполнять вычисления, которые будут выполняться при динамической инициализации, при условии, что эти расчеты не имеют побочных эффектов. Кроме того, эти вычисления не должны зависеть от внешней среды. В приведенном выше примере:

(1) может быть выполнен статически, так как strlen() не имеет побочных эффектов.

(2) должен оставаться динамическим, поскольку он мутирует a.

(3) должен оставаться динамическим, так как он зависит от внешней среды/делает системные вызовы.

(4) может быть выполнен статически.

(5) немного сложнее, поскольку вычисление с плавающей запятой зависит от состояния FPU (а именно, режима округления). Если компилятору предлагается не относиться к арифметике с плавающей запятой серьезно, то ее можно выполнить статически.

+0

Спасибо за ваш ответ. Итак, в вашем примере, если c инициализируется статически, будет ли пропущен конструктор, когда c.i установлен равным 123? Если это так, согласно первому абзацу в [class.cdtor]: «Для объекта с нетривиальным конструктором, ссылаясь на любой нестатический член или базовый класс объекта до того, как конструктор начнет выполнение, результат приведет к неопределенному поведению», любой дополнительный доступ к ci в вашем примере приведет к неопределенному поведению, хотя он имеет четкое значение 123, как невероятно! Или есть некоторые ошибки в вышеупомянутом анализе? – xskxzr

+0

Для примера кода конструктор можно считать выполненным, поскольку его единственным эффектом является установка 'c.i'' 123'. Тот факт, что компилятор несколько перестроил то, как это было сделано, - это просто деталь реализации. – Leon

+0

Что делать, если существуют побочные эффекты? [basic.start.static/3], похоже, не требует никаких побочных эффектов. – xskxzr

Смежные вопросы