Создает ли приращение в списке инициализатора члена неопределенное поведение?

Это вызывает неопределенное поведение? В частности, увеличение в списке инициализатора и как это будет оцениваться.

class Wrinkle {
public:
    Wrinkle(int i) : a(++i), b(++i), x(++i) {}
private:
    int a;
    int x;
    int b;
};

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

2 ответа

Решение

Это не генерирует неопределенное поведение, потому что:

[class.base.init] # 7

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

[intro.execution]

5. Полное выражение

  • [...]
  • init-декларатор или mem-initializer, включая составные выражения инициализатора,

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


Но будьте осторожны, что:

[class.base.init] # 13

В не делегирующем конструкторе инициализация происходит в следующем порядке:

  • [...]

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

Таким образом, ваш код будет эффективно назначать i + 1 в a, i + 2 в x а также i + 3 в b,

Стандарт C++17 содержит пример, почти такой же, как в вопросе:

struct B1 { B1(int); /* ... */ };
struct B2 { B2(int); /* ... */ };
struct D : B1, B2 {
  D(int);
  B1 b;
  const int c;
};

D::D(int a) : B2(a+1), B1(a+2), c(a+3), b(a+4) { /* ... */ }
D d(10);

Далее следует примечание:

[Примечание: инициализация, выполняемая каждым mem-initializer, составляет полное выражение (4.6). Любое выражение в mem-initializer оценивается как часть полного выражения, которое выполняет инициализацию. - конец примечания]

Перейдя по ссылке, раздел 4.6 сообщает, что одно из определений "полного выражения"

... mem-initializer, включая составляющие выражения инициализатора,

Фраза "в том числе составные выражения initiailizer" настоятельно предполагает мне, что приведенный выше код является законным, потому что побочные эффекты ++i будет завершено, прежде чем перейти к следующему инициализатору. Это всего лишь мое прочтение стандарта, хотя я с радостью полагаюсь на любого, у кого больше опыта, чем у меня.

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

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