Зависимости в списках инициализации

Является ли это поведение четко определенным?

class Foo
{
    int A, B;

    public:

    Foo(int Bar): B(Bar), A(B + 123)
    {
    }
};

int main()
{
    Foo MyFoo(0);
    return 0;
}



Ответы (3)


Нет, это не определено. A будет инициализирован первым (он первый в определении класса), и он использует неинициализированный B.

Члены класса инициализируются в том порядке, в котором они указаны в определении класса, независимо от их порядка в списке инициализации. Действительно, несоответствие порядка определения членов порядку списка инициализации является плохой практикой.

Если ваш экземпляр Foo имел статическую продолжительность, как в Foo f(0); int main(){}, поведение четко определено. Объекты со статической продолжительностью инициализируются нулями до того, как произойдет любая другая инициализация; в этом случае A и B будут равны 0 при запуске конструктора. Однако после этого поведение такое же: сначала A, затем B, присваивая A значение 123, а B значение Bar (все еще уродливо).

person GManNickG    schedule 09.06.2011
comment
Верно. Лучшим способом написать конструктор будет Foo(int Bar): A(Bar + 123), B(Bar) { }. - person Kerrek SB; 09.06.2011
comment
Одно примечание: gcc (по крайней мере) выдает предупреждение, если в списке инициализации атрибуты не перечислены в том же порядке, в котором они объявлены в классе/структуре. - person Matthieu M.; 09.06.2011
comment
@Matthieu Да, но для этого необходимо включить -Wextra. - person Maxpm; 09.06.2011
comment
@Maxpm: я думаю, что -Wall было бы достаточно, хотя я согласен, что было бы здорово, если бы он был активен по умолчанию. - person Matthieu M.; 10.06.2011

Нет, порядок инициализации определяется порядком объявления в самом классе.

Из стандарта С++ 12.6.2 [class.base.init] p5:

Инициализация должна выполняться в следующем порядке:
— Сначала и только для конструктора наиболее производного класса, как описано ниже, виртуальные базовые классы должны быть инициализированы в том порядке, в котором они появляются при обходе в глубину слева направо. ориентированного ациклического графа базовых классов, где «слева направо» — порядок появления имен базовых классов в списке-спецификаторов-базовых-производных классов.
— Затем в порядок объявления в том порядке, в котором они появляются в списке спецификаторов базы (независимо от порядка инициализаторов памяти).
— Затем нестатические элементы данных должны быть инициализированы в том порядке, в котором они были объявлены в определении класса ( снова независимо от порядка мем-инициализаторов).
— Наконец, выполняется тело конструктора.
[Примечание: порядок объявления гарантирует, что базовые подобъекты и подобъекты-члены будут уничтожены в порядке, обратном инициализации. ]

person Xeo    schedule 09.06.2011

Инициализация выполняется в порядке появления в объявлении, а не в том порядке, в котором вы пишете его в конструкторе.

Посмотрите на этот вопрос, он чем-то похож: Список инициализаторов *аргумент* порядок оценки

person littleadv    schedule 09.06.2011