Является ли локальная статическая переменная инициализацией потокобезопасной в С++ 11?

Я знаю, что это часто задаваемый вопрос, но, поскольку существует так много вариантов, я хотел бы переформулировать его и, надеюсь, иметь ответ, отражающий текущее состояние. Что-то вроде

Logger& g_logger() {
    static Logger lg;
    return lg;
}

Является ли конструктор переменной lg гарантированно работать только один раз?

Я знаю из предыдущих ответов, что в С++ 03 это не так; в проекте С++ 0x это принудительно. Но я бы хотел получить более четкий ответ

  • В стандарте С++ 11 (не черновик) завершено ли поведение инициализации потокобезопасным?
  • Если приведенное выше да, в последних последних выпусках популярных компиляторов, а именно gcc 4.7, vc 2011 и clang 3.0, они правильно реализованы?

Ответ 1

Соответствующий раздел 6.7:

такая переменная инициализируется, когда первый элемент управления проходит через его объявление; такая переменная считается инициализированной после завершения ее инициализации. [...] Если элемент управления входит в объявление одновременно, а переменная инициализируется, одновременное выполнение должно ждать завершения инициализации.

Тогда есть сноска:

Реализация не должна вводить какой-либо тупик вокруг выполнения инициализатора.

Итак, вы в безопасности.

(Это, конечно, ничего не говорит о последующем доступе к переменной через ссылку.)

Ответ 2

- fno-threadsafe-statics также стоит упомянуть. В gcc:

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

Кроме того, посмотрите на старый поток Являются ли функции статических переменных потокобезопасными в GCC?