Стандарты программирования на С++. 101 правило и рекомендация | страница 84
Решение заключается в том, чтобы всегда писать инициализаторы членов в том же порядке, в котором эти члены объявлены в классе. В этом случае сразу становятся очевидными все некорректные зависимости между членами. Еще лучше полностью избегать зависимости инициализации одного члена от других.
Многие компиляторы (но не все) выдают предупреждение при нарушении этого правила.
[Cline99] §22.03-1] • [Dewhurst03] §52-53 • [Koenig97] §4 • [Lakos96] §10.3.5 • [Meyers97] §13 • [Murray93] §2.1.3 • [Sutter00] §47
48. В конструкторах предпочитайте инициализацию присваиванию
В конструкторах использование инициализации вместо присваивания для установки значений переменных-членов предохраняет от ненужной работы времени выполнения при том же объеме вводимого исходного текста.
Конструкторы генерируют скрытый код инициализации. Рассмотрим следующий код:
>class A {
> string s1_, s2_;
>public:
> A() { s1_ = "Hello, "; s2_ = "world"; }
>};
В действительности сгенерированный код конструктора выглядит так, как если бы вы написали:
>А() : s1_(), s2_() { s1_ = "Hello, "; s2_ = "world"; }
To есть объекты, не инициализированные вами явно, автоматически инициализируются с использованием их конструкторов по умолчанию, после чего выполняется присваивание значений с использованием их операторов присваивания. Чаще всего операторы присваивания нетривиальных объектов выполняют немного больше работы, чем конструкторы, поскольку работают с уже созданными объектами.
Таким образом, инициализация переменных-членов в списке инициализации дает код, лучше выражающий ваши намерения и обычно более быстрый и меньшего размера:
>А() : s1_("Hello, "), s2_("world ") { }
Эта методика не является преждевременной оптимизацией; это — избежание преждевременной пессимизации (см. рекомендацию 9).
Всегда выполняйте захват неуправляемого ресурса (например, выделение памяти оператором >new
, результат которого не передается немедленно конструктору интеллектуального указателя) в теле конструктора, а не в списке инициализации (см. [Sutter02]). Конечно, лучше всего вообще не использовать таких небезопасных и не имеющих владельца ресурсов (см. рекомендацию 13).
[Dewhurst03] §51, §59 • [Keffer95] pp.13-14 • [Meyers97] §12 • [Murray93] §2.1.31 • [Sutter00] §8, §47 • [Sutter02] §18
49. Избегайте вызовов виртуальных функций в конструкторах и деструкторах
Внутри конструкторов и деструкторов виртуальные функции теряют виртуальность. Хуже того — все прямые или косвенные вызовы нереализованных чисто виртуальных функций из конструктора или деструктора приводят к неопределенному поведению. Если ваш дизайн требует виртуальной передачи в производный класс из конструктора или деструктора базового класса, следует воспользоваться иной методикой, например, постконструкторами.