Подтвердить что ты не робот

Выполняются ли вызовы функций в списке инициализатора конструктора?

Рассмотрим:

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?

4b9b3361

Ответ 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-инициализатором, представляет собой полное выражение. Любое выражение в mem-инициализаторе оценивается как часть полного выражения, которое выполняет инициализацию.

указывает, что каждый инициализатор является полным выражением, и каждое полное выражение секвенировано: [intro.execution]/14

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

Ответ 2

Я знаю, что a инициализируется до b из-за порядка их объявления в структуре.

Это правда.

Моя интерпретация этого ограничения заключается в том, что a не может быть инициализирована до b, если оценка выражения инициализатора не завершена до того, как инициализируется b.

Я не вижу ничего в стандарте, который говорит о последовательности определения выражений, используемых для инициализации нестатических членов. Тем не менее, я вижу следующий пример в стандарте С++ 11 (12.6.2/12):

Имена в списке выражений или список бит-инициализации mem-инициализатора оцениваются в объеме конструктора, для которого указан mem-инициализатор. [Пример:

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.