Ответ 1
Компиляторы могут создавать различные типы кода.
Статический инициализированный сегмент данных
Компилятор передает в раздел данных имя и его начальное значение.
.data
dw myData 6
Это инициализируется во время компиляции и безопасно определяется на протяжении всего срока службы программы.
построенные данные
Другая альтернатива заключается в том, что компилятор резервирует некоторое пространство для этой переменной и создает инициализатор/конструктор для данных, а затем вызывает конструктор непосредственно перед main
. При выполнении деструктора (если требуется) atexit
.
class CriticalSection {
CRITICAL_SECTION m_myCS;
public:
CriticalSection() {
InitializeCriticalSection( &m_myCS );
}
~CriticalSection() {
DeleteCriticalSection( & m_myCS );
}
} cs;
в сочетании
Некоторые данные могут выполняться на обоих этапах.
struct Data {
bool initialized;
void *(*pMalloc)( size_t size );
} FixMalloc = { true, MyMalloc };
Я видел, как компиляторы (VS2013) генерируют код, который инициализирует initialized
значение true в статических данных, но создает функцию для назначения pMalloc
MyMalloc
во время выполнения. (Это объясняется тем, что для MyMalloc не была известна константа.)
метод singleton
SomeClass * GetSomeClass()
{
static SomeClass cls;
return &cls;
}
Этот порядок определен - когда он вызывается, но требует, чтобы компилятор полностью C++11
был потокобезопасным.
Резюме
Гарантии: -
- статики в одном модуле компиляции инициализируются сверху вниз.
- статика инициализируется однопоточной.
- синглтоны определили порядок построения. Но не обязательно безопасный поток.
Гарантии не являются: -
- Все объекты инициализируются одновременно.
- Статическая инициализация имеет рабочую среду выполнения.
Перед вызовом main, ваша статика и среда выполнения C/С++ являются загрузочными. Кроме того, порядок создания проблемы возникает между вашим кодом и временем выполнения, поэтому вы можете создавать некоторые элементы со сложными конструкторами, которые полагаются на службы, которые не могут быть доступны.