TGViewer
Грокаем C++ Грокаем C++ @grokaemcpp · 9.35K subscribers
Post #241 3.49K
​Правильный ответ - {мусор} {мусор} 5.

Список инициализации в конструкторе - вещь дельная, полезная и иногда без нее никуда. Но с ним есть один неприятный момент - все может пойти по шляпе, если не соблюдать одно правило. "Порядок инициализации полей в списке инициализации конструктора должен совпадать с порядком следования полей в описании класса". Но вот не все знают, что же будет, если это правило нарушить. Поэтому давайте разбираться.

Для начала приведу цитату из стандарта:

In a non-delegating constructor, initialization proceeds in the following order:

- First, and only for the constructor of the most derived class, virtual base classes
are initialized in the order they appear on a depth-first left-to-right traversal of the
directed acyclic graph of base classes, where “left-to-right” is the order of appearance
of the base classes in the derived class base-specifier-list.

- Then, direct base classes are initialized in declaration order as they appear in the 
base-specifier-list(regardless of the order of the mem-initializer)

- Then, non-static data members are initialized in the order they were declared in the
class definition (again regardless of the order of the mem-initializer()

- Finally, the compound-statement of the constructor body is executed.


Теперь разжуем эту сухую писанину в мягкую кашицу для лучшего усвоения.

В начале инициализируются базы класса в порядке, определяемом древовидной структурой наследования и ее проходом в глубину слева-направо. Не думаю, что сейчас надо что-то больше пояснять, как и про инициализацию статических полей. Ориентировочно 3.245 лайка на этот пост хватит, чтобы мы начали готовить про эти темы посты.

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

Ну и далее выполняется само тело конструктора.

Какие из этого выводы?

Самый главный - поведение абсолютно определено стандартом. Здесь нет никакого UB! Список инициализации лишь задает способ инициализации, но никак не влияет на порядок. Порядк определяется только порядком следования полей в описании класса(сверху вниз).

То есть в нашем примере в начале будет инициализировать b, потом a и, наконец, c. И не смотря на то, что в списке инициализации c стоит первым, на самом деле его инициализация будет проходить последней. А так как все остальные поля зависят от значения c и инициализируются раньше него, то в них будет содержаться мусор.

Никто нам не может запретить писать список инициализации в том порядке, в котором мы хотим. Да и непонятно, как это сделать. С точки зрения С++, код вполне корректен и может работать. Просто от этого будут последствия, но вполне предсказуемые.

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

Также вы можете(должны?) добавить флаг компиляции, чтобы превращать все предупреждения в ошибки. Тогда вы точно ничего важного не пропустите. Как говорится, флаг -Werror вам в руки!

Можете, кстати, поделиться в комментах историями, как у вас на проектах не стоял этот флаг, рекордным количеством неисправленных ворнингов и последствиями пренебрежением предупредпреждений.

Еще есть нюансы с default member initializer и его сочетанием со списком инициализации конструктора. Короче, много нюансов, как и во всех плюсах)
В один пост все все равно не влезет. Будем разделять и властвовать!

Devide et empera. Stay cool.

#cppcore
  • 👍 69
  • ❤ 10
  • 🔥 5
  • 👎 2
More from @grokaemcpp
  1. Oct 14, 2026​​Что внутри std::condition_variable? #опытным Более менее все знакомы с примитивом синхро…
  2. Oct 12, 2026​​WAT #новичкам Как вы думаете, результат выражения: bool math = -1 < 1U; будет правдой ил…
  3. Oct 8, 2026​​Strict weak ordering #опытным На первый взгляд, всё выглядит рабочим: мы создаём 40 зака…
  4. Oct 7, 2026​​Где-то баг... #опытным Вот вам код: struct Order { int price; int id; }; int main() { st…
  5. Oct 5, 2026Откуда spurious wakeup на кондваре? #опытным У кондваров есть метод std::condition_variabl…
  6. Oct 1, 2026​​Stacktrace. Tips #опытным Чтобы полноценно работать со стандартными трейсами, нужно знат…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →