The well-known Rule 1 — a const data member must be initialized exactly once, no more no less.
The lesser-known Rule 2 — for class-type data member, there’s an implicit default-initialization feature that can kick in without us knowing. This default-init interacts with ctor initializer in a strange manner.
On a side note, [[safeC++]] P38 makes clever use of Rule 2 to provide primitive wrappers. If you use such a wrapper in place of a primitive field (non-const), then you eliminate the operational risk of “
forgetting to initialize a non-const primitive field“
The well-known Rule 3 — the proper way to explicitly initialize a const field is the ctor initializer, not inside ctor body.
The lesser-known Rule 4 — at run-time, once control passes into the ctor body, you can only modify/edit an already-initialized field. Illegal for a const field.
To understand these rules, I created an experiment in https://github.com/tiger40490/repo1/blob/cpp1/cpp/lang_misc/constFieldInit.cpp
— for primitive fields like int, Rule 2 doesn’t apply, so we must follow Rule 1 and Rule 3.
— for a class-type field like “Component”,
- We can either leave the field “as is” and rely on the implicit Rule 2…., or
- If we want to initialize explicitly, we must follow Rule 3. In this case, the default-init is suppressed by compiler.
In either case, there’s only one initialization per const field (Rule 1)