Список инициализаторов для объектов с конструктором по умолчанию

Есть ли какая-либо польза от помещения переменной-члена класса в список инициализаторов, которая не обязательно должна быть в списке инициализаторов? Пример:

class Foo
{
public:
  Foo() {}
};

class Bar
{
public:
  Bar() : _foo() {}

private:
  Foo _foo;
};

Делает ли компилятор что-то особенное в этом случае?


person MarkP    schedule 05.11.2012    source источник
comment
_foo уже инициализирован (используя конструктор foo по умолчанию) из объявления Foo _foo; Если вы хотите повторно инициализировать _foo, используйте Bar() : _foo(Foo()) {}. Однако это было бы бессмысленно.   -  person andre    schedule 05.11.2012
comment
@ahenderson: Это неправильно. _foo инициализируется в списке инициализаторов. Это единственное место, где члены класса инициализируются. Bar() : _foo(Foo()) {} не повторно инициализирует _foo — он инициализирует его.   -  person John Dibling    schedule 05.11.2012
comment
@JohnDibling о, тогда я ошибся. Теперь я понимаю, прочитав ответ Керрека С.Б.   -  person andre    schedule 05.11.2012


Ответы (4)


Список инициализаторов является предпочтительным способом инициализации членов в конструкторе. Это единственный возможный способ инициализировать ссылочные и константные элементы.

Кроме того, используя список инициализаторов, вы уменьшаете вероятность случайного использования переменной до ее инициализации. Это часть более широкой философии никогда не определять переменную без ее инициализации.

person Syntactic Fructose    schedule 05.11.2012
comment
Следует отметить, что список должен быть в том же порядке, что и объявления. Это хорошая практика. - person Ed Heal; 05.11.2012
comment
ссылочные и константные члены могут быть инициализированы с помощью инициализации в классе (C++11). И для рассматриваемых типов список инициализаторов не влияет на возможность доступа к члену до его инициализации; элемент по умолчанию инициализируется одновременно в обоих случаях. - person bames53; 05.11.2012
comment
@EdHeal, это больше, чем хорошая практика. Они инициализируются в этом порядке, поэтому, если вы инициализируете один на основе другого, вам лучше поместить зависимый после независимого в классе. - person chris; 05.11.2012
comment
@chris - Да, я знаю - Просто хотел сделать пилюлю сладкой. Скотт Майерс. Не могу вспомнить номер в первой книге навскидку. - person Ed Heal; 05.11.2012

В данном случае это не имеет значения.

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

Примечание. Если вы поместите их в неправильном порядке в списке интернализации, это обычно просто предупреждение для большинства компиляторов (если вы не компилируете с предупреждениями как ошибками (что вам следует)).

Реальная опасность связана с классами, которые имеют элементы POD и конструктор, сгенерированный компилятором.

class NewFoo
{
      int x;
      int y;
};
// Version 1:
class Bar1
{
     NewFoo  f;
};
// Version 2:
class Bar2
{
     NewFoo  f;
     public:
         Bar2()  // f not in list.
         {}
};
// Version 3:
class Bar3
{
     NewFoo  f;
     public:
         Bar3()
            : f()
         {}
};

int main()
{
     Bar1     b1a;           // x and y not  initialized.
     Bar1     b1b = Bar1();  // x and y zero initialized.
     Bar2     b2a;           // x and y not  initialized.
     Bar2     b2b = Bar2();  // x and y not  initialized.
     Bar3     b3a;           // x and y zero initialized.
     Bar3     b3b = Bar3();  // x and y zero initialized.
}
person Martin York    schedule 05.11.2012
comment
+1 за этот реальный ответ. Я следую стилю, который вы советуете в течение многих лет, но теперь мне интересно, может ли тривиальное повторение членов быть просто шумом. Для структуроподобных классов, которые имеют только члены с конструкторами по умолчанию, не лучше ли использовать пустой список инициализаторов? - person Wolf; 04.04.2014
comment
@Волк: Да. Это все контекстуально. Вы должны использовать технику, облегчающую чтение кода. Если очевидно, что в вашем классе есть члены, которые создаются автоматически, тогда можно просто иметь пустой список. - person Martin York; 04.04.2014
comment
@Wolf: обновленный ответ с информацией. - person Martin York; 04.04.2014
comment
Bar3(): f() {} - это ничего не делает с моим компилятором (x, y не определены) - это функция С++ 11? - person Wolf; 04.04.2014
comment
@Wolf: Нет, это функция С++ 03. потому что вы явно вызываете инициализатор f. Это вызовет нулевую инициализирующую версию сгенерированного компилятором конструктора. Почему вы думаете, что они ничего не делают? Какой компилятор вы используете? - person Martin York; 04.04.2014
comment
Поведение C++03 имеет абсолютно смысл. Я в основном (и ненавижу) использовать компилятор BCB6 (Borland C++ 5.6.4), и он имеет очевидно, некоторые недостатки в списках инициализаторов ;) - person Wolf; 04.04.2014
comment
Я запускаю этот пример в Visual C++ 2013, и ни в одном из случаев x или y не обнуляются. Так это несоответствие VC++? - person Peter B; 13.08.2015
comment
В Visual Studio 2017 это работает так, как указано в комментариях. Спасибо за пример. - person Jarek C; 20.02.2019

Члены, не упомянутые в списке инициализаторов используемого конструктора, инициализируются по умолчанию. Для Foo это означает, что будет вызван конструктор по умолчанию.

Разница между Bar() : _foo() { } и полным отсутствием явного конструктора по умолчанию для Bar (или указанием Bar() = default заключается в том, что ваша версия не имеет тривиального конструктора по умолчанию. в остальном то же самое.

person Kerrek SB    schedule 05.11.2012
comment
Я предполагаю, что вопрос заключается в разнице между предоставленным пользователем конструктором с инициализатором и без него в списке инициализаторов для рассматриваемого члена, а не в разнице между предоставленным пользователем конструктором и конструктором, не предоставленным пользователем. - person bames53; 05.11.2012

Нет, ничего другого в этом случае не делается. Я не вижу никакой пользы в этом.

person bames53    schedule 05.11.2012
comment
Преимущество состоит в том, что вы не сбиваете с толку людей, обученных поиску списков инициализаторов. - person Cubic; 05.11.2012