Зачем нужно упорядочивать порядок имен членов списка инициализаторов?
Почему 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
Порядок списка инициализаторов имеет значение НЕ.
Объявление ваших членов в заголовке класса определяет порядок инициализации.
Это по дизайну и требуется, поскольку у вас может быть несколько команд, имеющих совершенно разные порядки списков списков.
Таким образом, ваши члены будут ВСЕГДА инициализироваться в порядке объявления.