Я также хочу написать текст об инициализации, на который я могу позже сослаться.
Сначала список возможностей.
- Пространство имен Статическое
- Класс Статический
- Локальный Статический
Статическое пространство имен
- Существует два метода инициализации. статическая (должна выполняться во время компиляции) и динамическая (должна выполняться во время выполнения) инициализация.
- Статическая инициализация происходит до любой динамической инициализации, независимо от отношений единиц трансляции.
- Динамическая Инициализация упорядочена в единице перевода, в то время как в статической инициализации нет определенного порядка. Объекты пространства имен одной и той же единицы трансляции динамически инициализируются в том порядке, в котором появляется их определение.
- Объекты типа POD, которые инициализируются константными выражениями, инициализируются статически. На их значение можно положиться при динамической инициализации любого объекта, независимо от отношений единиц трансляции.
- Если инициализация выдает исключение, вызывается
std::terminate
.
Примеры:
Следующая программа печатает A(1) A(2)
struct A {
A(int n) { std::printf(" A(%d) ", n); }
};
A a(1);
A b(2);
А следующее, основанное на том же классе, печатает A(2) A(1)
extern A a;
A b(2);
A a(1);
Предположим, что есть единица перевода, где msg
определяется следующим образом:
char const *msg = "abc";
Затем выводится следующее: abc
. Обратите внимание, что p
получает динамическую инициализацию. Но поскольку статическая инициализация (char const*
— это тип POD, а "abc"
— адресное постоянное выражение) msg
происходит до этого, это нормально, и msg
гарантированно будет правильно инициализирован.
extern const char *msg;
struct P { P() { std::printf("%s", msg); } };
P p;
- Динамическая инициализация объекта не обязательно должна происходить до main любой ценой. Однако инициализация должна произойти до первого использования объекта или функции его единицы перевода. Это важно для динамически загружаемых библиотек.
Статический класс
- Ведите себя как статика пространства имен.
- Существует отчет об ошибке о том, разрешено ли компилятору инициализировать статику класса при первом использовании функции или объекта его единицы трансляции (после main). Формулировка в стандарте в настоящее время разрешает это только для объектов области пространства имен, но, похоже, она намерена разрешить это и для объектов области класса. Прочитайте Объекты области пространства имен.
- Для статических классов, которые являются членами шаблонов, правило состоит в том, что они инициализируются только в том случае, если они когда-либо используются. Их неиспользование не приведет к инициализации. Обратите внимание, что в любом случае инициализация произойдет, как описано выше. Инициализация не будет отложена, поскольку она является частью шаблона.
Локальный статический
- Для локальной статики бывают особые правила.
- Объекты типа POD, инициализированные константным выражением, инициализируются перед входом в их блок, в котором они определены.
- Другие локальные статические объекты инициализируются при первом прохождении управления через их определение. Инициализация не считается завершенной, когда возникает исключение. Инициализация будет предпринята снова в следующий раз.
Пример. Следующая программа печатает 0 1
:
struct C {
C(int n) {
if(n == 0)
throw n;
this->n = n;
}
int n;
};
int f(int n) {
static C c(n);
return c.n;
}
int main() {
try {
f(0);
} catch(int n) {
std::cout << n << " ";
}
f(1); // initializes successfully
std::cout << f(2);
}
Во всех вышеперечисленных случаях, в некоторых ограниченных случаях, для некоторых объектов, которые не требуют статической инициализации, компилятор может инициализировать их статически, а не динамически. Это сложная проблема, см. va/921681#921681">этот ответ для более подробного примера.
Также обратите внимание, что порядок разрушения является точным порядком завершения строительства объектов. Это обычное дело и происходит во всех ситуациях в C++, в том числе при уничтожении временных файлов.
person
Johannes Schaub - litb
schedule
03.07.2009