Порядок инициализации компонента класса - PullRequest
11 голосов
/ 29 июня 2011
class D: A
{
    B obj;
    C obj2;
}

Какой порядок строительства здесь гарантируется ?

Я знаю, что D будет построен после A, B и C, но я действительно хочу знать, является ли A гарантированным , который будет построен до B или C, или даже если B гарантировано будет построено до C.

Я знаю, что вы можете иметь явный список инициализаторов:

D(): A(), B(), C()
{}

но определяет ли этот список инициализатора порядок инициализации?

Кроме того, имеет ли какой-либо из компонентов конструктор по умолчанию или нет?

Ответы [ 3 ]

10 голосов
/ 29 июня 2011

Из стандарта C ++ 03 ISO / IEC 14882: 2003 (E) §12.6.2 / 5 [class.base.init]:

Инициализация должна выполняться в следующем порядке:
- Во-первых, и только для конструктора самого производного класса, как описано ниже, виртуальные базовые классы должны быть инициализированы в том порядке, в котором они отображаются при обходе слева направо по глубине направленного ациклического графа базовых классов.где «слева направо» - порядок появления имен базовых классов в производном классе список базовых спецификаторов .
- Затем прямые базовые классы должны быть инициализированы в порядке объявлениякак они появляются в base-specier-list (независимо от порядка mem-инициализаторов ).
- Затем нестатические элементы данных должны быть инициализированы в том порядке, в котором онибыли объявлены в определении класса (опять же независимо от порядка mem-инициализаторов ).
- Наконец, тело конструктора выполняется.
[ Примечание: theПорядок объявления должен обеспечивать уничтожение базовых и дочерних подобъектов в обратном порядке инициализации.]

Таким образом, в этом случае вам гарантируется, что порядок инициализации будет сначала базовым классом A, а затем подобъектом B (так как он появляется первым в списке членов классав определении класса), то подобъект C.Порядок списка инициализаторов не имеет значения, как и то, имеет ли какой-либо из членов конструктор по умолчанию или нет, если у члена нет конструктора по умолчанию, и он явно не инициализирован в списке инициализатора, тогда он имеетнеопределенное значение.

9 голосов
/ 29 июня 2011

но определяет ли этот инициализатор ПОРЯДОК инициализации?

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

struct A : B, C {}  //B is constructed before C

Кроме того, базовые подобъекты создаются до инициализации данных элемента.

struct A : B, C 
{
      D d;
      E e;
};

Порядок инициализации в приведенной выше структуре:

    B     =>    C      =>   d    =>   e   
subobject   subobject     member    member

И они уничтожены в обратном порядке.

1 голос
/ 29 июня 2011

Возможно, этот пример неработающего кода поможет проиллюстрировать:

Если я определю класс следующим образом:

class Connection {

   boost::asio::tcp::ip::socket _socket;
   boost::asio::io_service _io_service;

   Connection() : _io_service(), _socket(_io_service)
   {
   }
};

Это не удастся во всех современных компиляторах.Поскольку _socket определяется сначала как член класса, список инициализации попытается сначала его инициализировать, несмотря на тот факт, что список инициализации просит компилятор сначала инициализировать _io_service.Но поскольку _io_service еще не было инициализировано (конструктор сокета зависит от инициализированного _io_service), инициализация _socket вызовет ошибку segf.

Возможно, кто-то может процитировать соответствующий раздел стандартаэто диктует такое поведение.

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

...