Рассматривать:
int f () {
static int i = 0;
return i++;
}
struct Test {
int a, b;
Test () : a(f()), b(f()) {}
};
Test t;
я знаю это a
инициализируется раньше b
в связи с порядком их объявления в struct
,
Я также знаю, что два звонка f
в g(f(), f())
не секвенированы.
Так что мне интересно, если это гарантировано, что t.a == 0
а также t.b == 1
?
Так что мне интересно, если это гарантировано, что
t.a == 0
а такжеt.b == 1
?
Это всегда будет так до тех пор, пока a
приходит раньше b
в объявлении класса и ничего больше не вызывает f()
между инициализацией a
а также b
, Члены класса инициализируются в порядке их объявления в классе. [Class.base.init] / 11:
В не делегирующем конструкторе инициализация происходит в следующем порядке: […]
- Затем не статические члены данных инициализируются в порядке, в котором они были объявлены в определении класса (опять же, независимо от порядка mem-инициализаторов).
Так как a
приходит раньше b
затем, когда конструктор инициализирует a
это позвонит f()
в первый раз, а затем он будет вызывать его во второй раз, когда он инициализирует b
,
Мы также знаем, что существует точка последовательности между инициализатором члена, потому что [class.base.init] / 7:
[…] Инициализация, выполняемая каждым mem-initializer, представляет собой полное выражение. Любое выражение в mem-initializer оценивается как часть полного выражения, которое выполняет инициализацию.
говорит нам, что каждый инициализатор является полным выражением, и каждое полное выражение упорядочено: [intro.execution] / 14
Каждое вычисление значения и побочный эффект, связанный с полным выражением, упорядочивается перед каждым вычислением значения и побочным эффектом, связанным со следующим полным выражением, которое будет оценено.
Я знаю, что a инициализируется до b из-за порядка их объявления в структуре.
Это правда.
Моя интерпретация этого ограничения заключается в том, что a
не может быть инициализирован раньше b
если оценка выражения инициализатора не завершена до b
инициализируется.
Я не вижу в стандарте ничего, что говорило бы о последовательности вычислений выражений, используемых для инициализации нестатических элементов. Тем не менее, я вижу следующий пример в стандарте C ++ 11 (12.6.2 / 12):
Имена в списке выражений или в скобках-инициализаторе mem-initializer оцениваются в области действия конструктора, для которого указывается mem-initializer. [ Пример:
class X { int a; int b; int i; int j; public: const int& r; X(int i): r(a), b(i), i(i), j(this->i) { } };
Это не будет действительным, если оценка this->i
секвенируется после i
инициализируется.