Вопрос не требует, чтобы синглтон был ленивым или нет.
Поскольку многие ответы предполагают это, я предполагаю, что для первой фразы обсудим:
Учитывая тот факт, что сам язык не поддерживает потоки и плюс метод оптимизации, написание переносимого надежного синглтона на С ++ очень сложно (если не невозможно), см. « С ++ и опасности двойной проверки». Блокировка"Скотта Мейерса и Андрея Александреску.
Я видел, что многие из ответов прибегают к синхронизации объекта на платформе Windows с помощью CriticalSection, но CriticalSection безопасен только для потоков, когда все потоки работают на одном процессоре, сегодня это, вероятно, неверно.
MSDN cite: «Потоки одного процесса могут использовать объект критической секции для синхронизации взаимного исключения.».
А http://msdn.microsoft.com/en-us/library/windows/desktop/ms682530(v=vs.85).aspx
уточнить это далее:
Объект критической секции обеспечивает синхронизацию, аналогичную предоставленной объектом мьютекса, за исключением того, что критическая секция может использоваться только потоками одного процесса.
Теперь, если «ленивое построение» не является обязательным требованием, следующее решение является кросс-модульным, безопасным для потоков и даже переносимым:
struct X { };
X * get_X_Instance()
{
static X x;
return &x;
}
extern int X_singleton_helper = (get_X_instance(), 1);
Это межмодульно-безопасно, потому что мы используем статический объект локальной области вместо глобального объекта области файла / пространства имен.
Это потокобезопасно, потому что: X_singleton_helper должен быть назначен правильному значению перед вводом main или DllMain. Это не ленивый и из-за этого факта), в этом выражении запятая является оператором, а не пунктуацией.
Явно используйте здесь «extern», чтобы не допустить его оптимизации компилятором (касается статьи Скотта Мейерса, большой враг - оптимизатор), а также заставьте инструмент статического анализа, такой как pc-lint, хранить молчание. «Прежде чем main / DllMain» Скотт Мейер назвал «однопоточной частью запуска» в «Effective C ++ 3rd», пункт 4.
Однако я не совсем уверен, разрешено ли компилятору оптимизировать вызов get_X_instance () в соответствии со стандартом языка, пожалуйста, прокомментируйте.