Инициализация класса С++, содержащая инициализацию переменной класса
Сегодня я заметил некоторый код коллеги, который инициализировал переменные класса в инициализации. Однако он вызывал предупреждение, говорит он из-за заказа, в котором они находятся. Мой вопрос: почему лучше делать инициализацию переменных там, где она сейчас есть, а не внутри фигурных скобок?
DiagramScene::DiagramScene( int slideNo, QRectF screenRect, MainWindow* parent )
: QGraphicsScene( screenRect, parent ),
myParent( parent ),
slideUndoImageCurrentIndex(-1),
nextGroupID(0),
m_undoInProgress(false),
m_deleteItemOnNextUndo(0)
line(0),
path(0)
{
/* Setup default brush for background */
scDetail->bgBrush.setStyle(Qt::SolidPattern);
scDetail->bgBrush.setColor(Qt::white);
setBackgroundBrush(scDetail->bgBrush);
}
Ответы
Ответ 1
- Это более эффективно (в общем). Все члены класса инициализируются в конструкторе, независимо от того, явно ли вы их инициализируете или нет. Если вы не укажете инициализатор, будет запущен конструктор по умолчанию элемента. Если вы назначаете значение в теле конструктора, то оператор присваивания снова вызывается. Это не относится к скалярным значениям, как в вашем примере, поскольку в скалярных значениях нет конструкторов.
- Вы не можете случайно присвоить значение дважды в списке инициализации.
- Компилятор может проверить, чтобы порядок, в котором вы пишете инициализаторы, соответствует порядку, в котором члены определены в классе. Стандарт С++ требует, чтобы члены были инициализированы в том порядке, в котором они объявлены, независимо от порядка, который вы пишете инициализаторы. Проверка этого компилятора гарантирует, что программист знает, в каком порядке будут запускаться инициализаторы (опять же, это более важно для не-POD-элементов, чем для скаляров).
- Типы ссылок и члены
const
должны быть инициализированы в списке инициализации, потому что вы не можете назначить ссылку или члену const
.
Ответ 2
Лучше выполнить инициализацию членов в списке инициализации, потому что члены затем инициализируются только один раз. Это может быть огромная разница в производительности (и даже в поведении), если члены сами являются классами. Если все члены являются неконстантными, неосновными фундаментальными типами данных, то разница обычно незначительна.
ПРИМЕЧАНИЕ. Бывают случаи, когда для основных типов данных требуются списки инициализации, особенно если тип является постоянным или ссылкой. Для этих типов данные могут быть инициализированы только один раз и поэтому не могут быть инициализированы в теле конструктора. Подробнее см. в этой статье.
Обратите внимание, что порядок инициализации членов - это порядок, в котором члены объявляются в определении класса, а не порядок, в котором члены объявлены в списке инициализации. Если предупреждение можно устранить, изменив порядок списка инициализации, я настоятельно рекомендую вам это сделать.
Это моя рекомендация:
- Вы учитесь любить списки инициализации.
- Ваш сотрудник понимает правила для порядка инициализации членов (и избегает предупреждений).
Ответ 3
В дополнение к Greg Hewgill отличный ответ - константные переменные должны быть установлены в списке инициализации.
Ответ 4
Потому что в теле конструктора ( "внутри фигурных скобок" ) переменные-члены уже построены по умолчанию. Это может иметь некоторые последствия для производительности, когда у вас есть переменная-член типа, которая имеет нетривиальную конструкцию, когда вы сначала создаете ее по умолчанию, а затем присваиваете ей какое-то другое значение в конструкторе, когда у вас может быть пользовательская конструкция это прямо.
Кроме того, некоторые типы могут не создаваться по умолчанию (например, ссылки) и должны быть сконструированы в списке инициализации.
Ответ 5
Если у вас есть константные переменные, их значение не может быть задано с помощью присваивания.
Инициализация также является более эффективной при назначении значений объектам (не встроенным или внутренним), поскольку временный объект не создается, как это было бы для назначения.
Подробнее см. С++ FAQ-Lite
Ответ 6
Взгляните на собранную мудрость на http://web.tiscali.it/fanelia/cpp-faq-en/ctors.html#faq-10.6
Ответ 7
Другое дополнение к ответу Грега: члены, имеющие типы без конструктора по умолчанию, должны быть инициализированы в списке инициализации.
Ответ 8
Ответ Грега Хегвелла содержит отличный совет, но он не объясняет, почему компилятор генерирует предупреждение.
Когда список инициализатора конструктора обрабатывается компилятором, элементы инициализируются в том порядке, в котором они объявлены в объявлении класса, а не в том порядке, в котором они отображаются в списке инициализаторов.
Некоторые компиляторы генерируют предупреждение, если порядок в списке инициализаторов отличается от порядка объявления (так что вы не будете удивлены, когда элементы не будут инициализированы в порядке списка). Вы не включаете объявление своего класса, но это вероятная причина предупреждения, которое вы видите.
Обоснование такого поведения состоит в том, что члены класса всегда должны быть инициализированы в том же порядке: даже если класс имеет более одного конструктора (который может иметь элементы, упорядоченные по-разному в своих списках инициализации).