Могут ли переменные-члены использоваться для инициализации других членов в списке инициализации?
Рассмотрим следующую (упрощенную) ситуацию:
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) и, похоже, работает, но я не уверен, что этот код переносимый.
Спасибо за вашу помощь!
Ответы
Ответ 1
Это хорошо определено и переносимо, 1 но оно потенциально подвержено ошибкам.
Члены инициализируются в том порядке, в котором они объявлены в классе, а не в порядке, указанном в списке инициализации. Поэтому, если вы измените тело класса, этот код может бесшумно (хотя многие компиляторы обнаружат это и выдают предупреждение).
<Суб > 1. Из [class.base.init] в стандарте (-ях) С++:
В конструкторе без делегирования инициализация выполняется в следующем порядке:
- Во-первых, и только для конструктора самого производного класса (1.8) виртуальные базовые классы инициализируются в порядок, который они появляются при первом обратном направлении слева направо направленного ациклического графа базовых классов, где "слева направо" - порядок появления базовых классов в базовом-спецификаторе-списке производного класса.
- Затем прямые базовые классы инициализируются в порядке объявления, как они появляются в списке-спецификаторе-базы (независимо от порядка mem-инициализаторов).
- Затем нестатические члены данных инициализируются в том порядке, в котором они были объявлены в определении класса(опять же независимо от порядка mem-инициализаторов).
- Наконец, выполняется составная инструкция тела конструктора.
(Подчеркивание - мое.)
В этом разделе стандарта далее приводится пример использования переменных-членов для инициализации других переменных-членов.
Суб >
Ответ 2
Да, убедитесь, что они уже построены. Просто не забывайте
что порядок построения - это порядок заявлений в
определение класса, а не порядок инициализаторов в
конструктор. И что компилятор обычно не скажет вам, используете ли вы
переменная до ее построения. В вашем случае, например,
если вы переместите evenSum
в начало класса, у вас есть undefined
поведение (потому что его инициализатор использует неинициализированные элементы), даже
хотя в вашем конструкторе вы инициализируете evenA
и evenB
лексически
до evenSum
.
Ответ 3
Члены инициализируются в том порядке, в котором они объявлены в определении класса. Пока ваш список инициализаторов следует этому порядку, он должен быть в порядке.
Ответ 4
Это также скомпилировано без ошибок в g++ 4.0.3 (теперь 6 лет).
Я уверен, что это скомпилирует любой разумный компилятор.