Зачем нужно упорядочивать порядок имен членов списка инициализаторов?

Почему gcc бросает шипение, если порядок списка инициализаторов не соответствует переменному порядку в классе?

class myClass
{
public:
   int A;
   int B;
   myClass();
};

myClass::myClass() :
B(1),
A(2)
{}

приведет к:

file.h:274: warning: 'myClass::A' will be initialized after
file.h:273: warning:   'int myClass::B
file.cpp:581: warning:   when initialized here

Есть ли какая-то конкретная причина, почему этот вид предупреждения выдается? Существуют ли какие-либо риски, связанные с инициализацией переменных класса в порядке, отличном от того, что они определены внутри класса?

(обратите внимание, что есть вопрос , который затрагивает тему, но ответы в значительной степени "потому что это должно быть так", не давая никаких объяснений относительно того, почему это должен быть заказан, или что не так с этим не в порядке - я хотел бы знать, почему такое ограничение существует - может ли кто-нибудь привести пример, где он может иметь неприятные последствия?)

Ответы

Ответ 1

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

myClass::myClass() :
B(42), A(B) {}

Здесь у вас есть поведение undefined, потому что вы читаете из неинициализированного B.

Ответ 2

Предупреждение указывает, что независимо от порядка, который вы используете в списке инициализации конструктора, стандарт требует, чтобы нестатические элементы данных были инициализированы в том порядке, в котором они были объявлены. Мы можем это увидеть, перейдя в проект стандарта С++ 12.6.2 Инициализация баз и членов параграфа 10, в котором говорится:

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

и включает в себя:

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

Почему стандарт требует этого? Мы можем найти обоснование для этого в статье Эволюция С++: 1985 - 1989 гг. Bjarne Stroustrup в разделе 6 говорится:

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

[...]

Причиной игнорирования порядка инициализаторов является сохранение обычное упорядочение FIFO вызовов конструктора и деструктора. Разрешение двух конструкторы использовать разные порядки инициализации баз и члены будут ограничивать реализации более динамичным и более дорогостоящие стратегии

Ответ 3

Порядок списка инициализаторов имеет значение НЕ. Объявление ваших членов в заголовке класса определяет порядок инициализации.

Это по дизайну и требуется, поскольку у вас может быть несколько команд, имеющих совершенно разные порядки списков списков.

Таким образом, ваши члены будут ВСЕГДА инициализироваться в порядке объявления.