Classes and class hierarchies
C.48
Предпочитайте инициализаторы членов по умолчанию инициализаторам членов в конструкторах для постоянных инициализаторов
Причина
Делает явным, что одно и то же значение должно использоваться во всех конструкторах. Избегает повторения. Избегает проблем с обслуживанием. Это приводит к самому короткому и эффективному коду.
Плохой пример
class X { // ПЛОХО
int i;
string s;
int j;
public:
X() :i{666}, s{"qqq"} { } // j не инициализировано
X(int ii) :i{ii} {} // s это "" и j не инициализировано
// ...
};
Как разработчик узнает, был ли j намеренно не инициализирован (вероятно, плохая идея в любом случае) и было ли намерением дать s значение по умолчанию "" в одном случае и qqq в другом (почти наверняка ошибка)? Проблема с j (забывание инициализировать член) часто происходит при добавлении нового члена к существующему классу.
Пример
class X2 {
int i {666};
string s {"qqq"};
int j {0};
public:
X2() = default; // все члены инициализируются их значениями по умолчанию
X2(int ii) :i{ii} {} // s и j инициализируются их значениями по умолчанию
// ...
};
Альтернатива: Мы можем получить часть преимуществ от аргументов конструктора по умолчанию, и это не редко в старом коде. Однако это менее явно, вызывает больше аргументов и повторяется, когда есть более одного конструктора:
class X3 { // ПЛОХО: неявное, накладные расходы на передачу аргументов
int i;
string s;
int j;
public:
X3(int ii = 666, const string& ss = "qqq", int jj = 0)
:i{ii}, s{ss}, j{jj} { } // все члены инициализируются их значениями по умолчанию
// ...
};
Применение
- (Простое) Каждый конструктор должен инициализировать каждый член данных (либо явно, через вызов конструктора-делегата, либо через конструирование по умолчанию).
- (Простое) Аргументы конструктора по умолчанию предполагают, что инициализатор члена по умолчанию может быть более подходящим.