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

Могут ли переменные-члены использоваться для инициализации других членов в списке инициализации?

Рассмотрим следующую (упрощенную) ситуацию:

class Foo
{
private:
    int evenA;
    int evenB;
    int evenSum;
public:
    Foo(int a, int b) : evenA(a-(a%2)), evenB(b-(b%2)), evenSum(evenA+evenB)
    {
    }
};

Когда я устанавливаю Foo следующим образом:

Foo foo(1,3);

то даже A равно 0, даже B равно 2, но будет даже SSN инициализировано до 2?

Я пробовал это на своей текущей платформе (iOS) и, похоже, работает, но я не уверен, что этот код переносимый.

Спасибо за вашу помощь!

4b9b3361

Ответ 1

Это хорошо определено и переносимо, 1 но оно потенциально подвержено ошибкам.

Члены инициализируются в том порядке, в котором они объявлены в классе, а не в порядке, указанном в списке инициализации. Поэтому, если вы измените тело класса, этот код может бесшумно (хотя многие компиляторы обнаружат это и выдают предупреждение).


<Суб > 1. Из [class.base.init] в стандарте (-ях) С++:

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

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

(Подчеркивание - мое.)

В этом разделе стандарта далее приводится пример использования переменных-членов для инициализации других переменных-членов. Суб >

Ответ 2

Да, убедитесь, что они уже построены. Просто не забывайте что порядок построения - это порядок заявлений в определение класса, а не порядок инициализаторов в конструктор. И что компилятор обычно не скажет вам, используете ли вы переменная до ее построения. В вашем случае, например, если вы переместите evenSum в начало класса, у вас есть undefined поведение (потому что его инициализатор использует неинициализированные элементы), даже хотя в вашем конструкторе вы инициализируете evenA и evenB лексически до evenSum.

Ответ 3

Члены инициализируются в том порядке, в котором они объявлены в определении класса. Пока ваш список инициализаторов следует этому порядку, он должен быть в порядке.

Ответ 4

Это также скомпилировано без ошибок в g++ 4.0.3 (теперь 6 лет).

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