Допустимые выходы: 1/2, 2 и 2 / 1.
Если инициализация переменной foo
имеет значение , а не отложено, то она упорядочивается до начала main
, поэтому 1
печатается до 2
.
Если инициализация откладывается, то требуется, чтобы инициализация foo
происходила до (любого) odr-использования из foo
. Это не говорит о том, что инициализация не должна происходить, если не используется odr. Вывод 2/1 определенно будет очень странным для этого примера (а вывод 2 - единственный, используемый на практике реализациями, которые откладывают инициализацию), но я не вижу в стандарте ничего, что строго исключало бы его.
Я полагаю, что причина для формулировки в стандарте состоит в том, что он позволяет реализациям использовать одну защиту для отсрочки инициализации всех таких переменных в единице перевода. Если мы изменим ваш пример следующим образом:
…
Foo foo;
struct Bar {
Bar() { std::cout << "3\n"; }
void Use() {}
} bar;
int main()
{
std::cout << "2" << std::endl;
bar.Use();
}
С одной защитой и отложенной инициализацией foo
будет инициализирован вместе с bar
, даже если в программе нет использования odr (кроме инициализации) foo
. В этом случае это также требуется для согласованности, поскольку в примере используется упорядоченная инициализация , поэтому инициализация foo
должна быть упорядочена до bar
, поэтому единственные допустимые выходы - 1/3/2 ( без отложенной инициализации) и 2/1/3 (отложенная инициализация). Но если бы мы использовали другую конструкцию для получения неупорядоченной инициализации, реализация также могла бы выдать 2/3/1
(опять же, без использования инициализации odr foo
).