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

Если у меня есть класс, который объединяет другие объекты, которые имеют взаимозависимости, (как) я должен применять их порядок построения?

Например.

class Parent
{
Child1 c1;
Child2 c2;
};

Представьте, что конструктор Child2 требует Child1& и я хочу передать в c1 конструкторам c2.

Если я просто сделаю следующее …

Parent::Parent()
: c2(c1)
{
}

…это может быть нехорошо, так как c1 не может быть создан ко времени запуска инициализатора для c2? Или это достаточно хорошо, что c1 стоит перед c2 в объявлении класса?

Или я должен явно ссылаться на конструктор c1 (если это не обязательно, то рекомендуется ли делать это, чтобы сделать его явным?). Например.

class Parent
{
Child1 c1;
Child2 c2;
};

Parent::Parent()
: c1()
: c2(c1)
{
}

1

Решение

Элементы всегда создаются в том порядке, в котором они объявлены. Так что если у вас есть:

class Parent
{
Child1 c1;
Child2 c2;
};

вам гарантировано, что c1 будет построен раньше c2, Так что если c2 нужен Child1&тогда это совершенно четко определено:

Parent::Parent()
: c2(c1)
{
}

c1 будет построен по умолчанию, а затем c2 будет построен с определенно уже построен c1,

3

Другие решения

Все это не имеет никакого эффекта. Переменные-члены создаются в порядке их объявления. Полная остановка.

Вот полное объяснение от cppreference:

Порядок инициализаторов элементов в списке не имеет значения: фактический порядок инициализации следующий:

  1. Элемент списка
    Если конструктор предназначен для самого производного класса, виртуальные базовые классы инициализируются в том порядке, в котором они отображаются в порядке обхода слева направо в объявлениях базового класса (слева направо относится к появлению в базе). списки спецификаторов)
  2. Затем прямые базовые классы инициализируются в порядке слева направо, как они появляются в списке базовых спецификаторов этого класса.
  3. Затем нестатические члены-данные инициализируются в порядке объявления в определении класса.
  4. Наконец, тело конструктора выполняется
1

Порядок объявления в классе является единственной важной вещью. Порядок построения в списке инициализатора не соблюдается компилятором, действительно, вы можете включить предупреждение, предупреждающее вас об этом факте (порядок в списке инициализатора! = Порядок эффективной конструкции).

1

В c ++ члены в списке инициализаторов инициализируются не в том порядке, в котором вы их поместили в список, а в том порядке, в котором вы их объявили. Фактически, g ++ выдаст предупреждение, если вы не инициализируете элементы в том порядке, в котором вы их объявили. Таким образом, вы должны заботиться о объявлять члены в их логическом порядке — от более низкого уровня до более высокого уровня объекта.

1

Данные члена строятся в порядке объявления. Если c1 объявлен ранее c2 (как в ваших примерах), тогда он будет построен первым.

Однако между вашими двумя примерами есть небольшая разница:

Parent::Parent()
// c1 is implicitly default-initialized
: c2(c1)
{
}

Parent::Parent()
: c1(), //c1 is value-initialized
c2(c1)
{
}

Если Child1 это тип класса не POD, оба они эквивалентны, но в противном случае вы получите неопределенное значение для c1,

Если это важно для вас, вы можете прочитать о разнице между дефолт- а также Значение инициализация.

1
По вопросам рекламы [email protected]