Имеет ли значение порядок инициализаторов базового класса и инициализаторов переменных-членов? - PullRequest
1 голос
/ 13 января 2012

Значит ли порядок инициализаторов для конструктора класса?

Так скажи, что у меня есть:

class MyClass : BaseClass
{
      int a, b, c;

   public:
      MyClass(int);
}

например. 1:

MyClass::MyClass(int forBase) :
  a(7),
  b(14),
  c(28),
  BaseClass(forBase) { }

например. 2:

MyClass::MyClass(int forBase) :
  BaseClass(forBase),
  a(7),
  b(14),
  c(28) { }

Будет ли пример 1 делать что-то отличное от примера 2?

Ответы [ 3 ]

8 голосов
/ 13 января 2012

Будет ли пример 1 делать что-то отличное от примера 2?

Нет . Порядок инициализации определяется стандартом, а не порядком, в котором вы пишете инициализаторы:

[C++11: 12.6.2/10]: В не делегирующем конструкторе инициализация поступает в следующем порядке:

  • Во-первых, и только для конструктора самого производного класса (1.8), виртуальные базовые классы инициализируются в том порядке, в котором они отображаются при обходе слева направо по глубине направленного ациклического графа базовых классов, где «Слева направо» - это порядок появления базовых классов в списке базовых спецификаторов производного класса.
  • Затем прямые базовые классы инициализируются в порядке объявления по мере их появления в списке базовых спецификаторов (независимо от порядка инициализации mem) .
  • Затем не статические члены данных инициализируются в порядке, в котором они были объявлены в определении класса (опять же, независимо от порядка mem-инициализаторов) .
  • Наконец, составной оператор тела конструктора выполняется.

На самом деле, если вы пишете их в любом другом порядке, и одно зависит от другого, вас вполне могут предупредить об этом :

struct T {
   std::vector<int> v;
   int w;

   T(int w) : w(w), v(0, w) {}
};

int main() {
   T t(3);
}

// g++ 4.1.2:
// t.cpp: In constructor 'T::T(int)':
// Line 3: warning: 'T::w' will be initialized after
// Line 2: warning:   '__gnu_debug_def::vector<int, std::allocator<int> > T::v'
// Line 5: warning:   when initialized here
4 голосов
/ 13 января 2012

Неважно, в каком порядке вы перечисляете инициализаторы в списке инициализации конструктора.Члены инициализируются в том порядке, в котором они были объявлены, а базы (и) инициализируются перед элементами.

Однако перечисление инициализаторов в другом порядке может вас укусить, если начальное значение подобъекта зависит от значений других подобъектов..

class A
{
  int y, x;
  A(int x_value): x(x_value), y(x) {}
};

Так как y инициализируется до x, он получает значение мусора, а порядок списка инициализатора просто скрывает ошибку.Вот почему это заслуживает предупреждения компилятора.

4 голосов
/ 13 января 2012

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

struct Derived: Base
{
  int member;
  Derived();
}

Derived::Derived():
  member(3),
  Base(member) // This is executed *before* member is initialized!
{
}

Эта ошибка выглядела бы более отчетливо, если бы инициализаторы были заданы в правильном порядке:

Derived::Derived():
  Base(member), // Now we see immediately that member is uninitialized
  member(3),
{
}
...