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

считаем:

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. Члены класса инициализируются в порядке их объявления в классе. [класс.основа.init] / 11:

в конструкторе без делегирования инициализация выполняется следующим образом порядок.[ :..]

  • затем нестатические члены данных инициализируются в том порядке, в котором они были объявлены в определении класса (опять же, независимо от порядка инициализаторов mem).

вот так a перед b затем, когда конструктор инициализирует a он будет вызывать f() в первый раз, а затем он вызовет его во второй раз, когда он инициализирует b.

мы также знаем, что есть точка последовательности между инициализатором члена, потому что [class.основа.init] / 7:

[...] Инициализация, выполняемая каждым инициализатором mem, представляет собой полное выражение. Любое выражение в инициализаторе mem оценивается как часть полного выражения, которое выполняет инициализацию.

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

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


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

это правда.

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

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

имена в expression-list или braced-init-list инициализатора 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 инициализируется.