47. Определяйте и инициализируйте переменные-члены в одном порядке

47. Определяйте и инициализируйте переменные-члены в одном порядке

Резюме

Переменные-члены всегда инициализируются в том порядке, в котором они объявлены при определении класса; порядок их упоминания в списке инициализации конструктора игнорируется. Убедитесь, что в коде конструктора указан тот же порядок, что и в определении класса.

Обсуждение

Рассмотрим следующий код:

class Employee {

 string email_, firstName_, lastName_;

public:

 Employee( const char* firstName, const char* lastName ) :

  firstName_(firstName), lastName_(lastName),

  email_(firstName_+"."+lastName_+"@acme.com") {}

};

Этот код содержит ошибку, столь же неприятную, сколь и трудно обнаруживаемую. Поскольку член email_ объявлен в определении класса до first_ и last_, он будет инициализирован первым и будет пытаться использовать еще не инициализированные поля. Более того, если определение конструктора находится в отдельном файле, то выявить такое удаленное влияние порядка объявления переменных-членов класса на корректность конструктора окажется еще труднее.

Эта особенность языка обусловлена необходимостью гарантировать единый порядок уничтожения членов; в противном случае деструктор был бы должен уничтожать объекты в разном порядке, в зависимости от того, в каком именно порядке конструктор создавал их. Накладные расходы, необходимые для решения этой проблемы, признаны неприемлемыми.

Решение заключается в том, чтобы всегда писать инициализаторы членов в том же порядке, в котором эти члены объявлены в классе. В этом случае сразу становятся очевидными все некорректные зависимости между членами. Еще лучше полностью избегать зависимости инициализации одного члена от других.

Многие компиляторы (но не все) выдают предупреждение при нарушении этого правила.

Ссылки

[Cline99] §22.03-1] • [Dewhurst03] §52-53 • [Koenig97] §4 • [Lakos96] §10.3.5 • [Meyers97] §13 • [Murray93] §2.1.3 • [Sutter00] §47