Последовательности вызовов функций в списке инициализатора конструктора?

Рассматривать:

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?

2 ответа

Решение

Так что мне интересно, если это гарантировано, что 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 инициализируется.

Другие вопросы по тегам