История вопроса:
В классическом C++ члены класса инициализировались только в списке инициализации конструктора. С C++11 появилась возможность указывать значения по умолчанию прямо в объявлении внутри класса (member initializers) для повышения читаемости и безопасности кода.
Проблема:
Существует несколько способов задать значение члену класса: непосредственно в объявлении (in-class), через список инициализации конструктора и уже в теле конструктора. Разные способы влияют на производительность и semantiku; неправильное понимание приводит к лишнему копированию или деструкторам по умолчанию, ошибкам с константами и ссылками.
Решение:
class MyClass { int x = 42; };
class MyClass { const int y; MyClass(int val) : y(val) {} // иначе — ошибка компиляции };
class MyClass { std::string s; MyClass() { s = "hello"; } // Сначала default, потом присвоение };
Ключевые особенности:
Каким будет порядок инициализации членов: в том порядке, в котором они объявлены в классе, или в порядке в списке инициализации?
Порядок инициализации всегда тот, в котором члены объявлены в классе, а не в порядке инициализации в списке. Нарушение порядка опасно для зависимых членов.
class A { int x = 1; int y = 2; A() : y(10), x(20) {} }; // x инициализируется раньше y, несмотря на порядок в списке
Можно ли инициализировать член-константу внутри тела конструктора, если она не была инициализирована в списке?
Нет. Константы инициализируются только в списке инициализации. Присвоение в теле конструктора — ошибка компиляции.
Что произойдет, если задать значение по умолчанию для члена прямо в классе через in-class initializer и переопределить его в списке инициализации конструктора?
Будет использовано значение из списка инициализации конструктора. Значение по умолчанию используется только если список ничего не указывает.
class C { int x = 10; C() : x(20) {} // x будет равно 20 };
Класс работает с файлом. Файл объявлен как std::ofstream, и инициализируется в теле конструктора. Опасность: при конструкторе по умолчанию может быть создан невалидный std::ofstream, что приводит к ошибкам работы с файлом.
Плюсы:
Минусы:
Файл инициализируется в списке инициализации, блокируя ошибочное использование файла с невалидным состоянием, а члены с дефолтными данными используют in-class initializer.
Плюсы:
Минусы: