Классный порядок инициализации
class D: A
{
B obj;
C obj2;
}
Какой порядок строительства здесь гарантирован?
Я знаю, что D будет построено после A, B и C, но то, что я действительно хочу знать, заключается в том, будет ли A гарантированно построено до B или C, или даже если B гарантированно будет построено до C.
Я знаю, что у вас может быть явный список инициализаторов:
D(): A(), B(), C()
{}
но этот список инициализации определяет порядок инициализации?
Кроме того, делает ли какой-либо из компонентов конструктор по умолчанию или нет?
Ответы
Ответ 1
Из стандарта С++ 03 ISO/IEC 14882: 2003 (E) §12.6.2/5 [class.base.init]:
Инициализация должна выполняться в следующем порядке:
- Во-первых, и только для конструктора самого производного класса, как описано ниже, виртуальные базовые классы должны быть инициализированы в том порядке, в каком они появляются на первом пересечении слева направо, направленном ациклическим графом базовых классов, где "слева направо" - это порядок появления имен базового класса в базе-спецификаторе производного класса.
- Затем прямые базовые классы должны быть инициализированы в порядке объявления, как они появляются в списке-спецификаторе-базовом (независимо от порядка mem-инициализаторов).
- Затем нестатические члены данных должны быть инициализированы в том порядке, в котором они были объявлены в определении класса (опять же, независимо от порядка mem-инициализаторов).
- Наконец, выполняется тело конструктора.
[Примечание: заказ декларации уполномочен гарантировать, что субобъекты базы и члена будут уничтожены в обратном порядке инициализации. ]
Итак, в этом случае вам гарантируется, что порядок инициализации будет сначала базовым классом A
, а затем подобъектом B
(поскольку он появляется первым в списке членов класса в определении класса), тогда подобъектом C
. Порядок списка инициализаторов не имеет значения, равно как и какой-либо из членов имеет или не имеет конструктора по умолчанию - если член не имеет конструктора по умолчанию и он явно не инициализирован в списке инициализаторов, то он имеет неопределенное значение.
Ответ 2
но этот список инициализации определяет ORDER инициализации?
Нет. Инициализационный список не определяет порядок инициализации данных-членов и базового подобъекта (ов). Члены инициализируются в порядке их объявления, а базовые подобъекты строятся в порядке их упоминания - слева направо:
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
И они уничтожены в обратном порядке.
Ответ 3
Возможно, этот пример разбитого кода поможет проиллюстрировать:
Если я определяю такой класс:
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
приведет к segfault.
Возможно, кто-то может процитировать соответствующий раздел стандарта, который диктует это поведение.
Во второй половине вопроса базовые классы всегда будут инициализированы перед собственными членами классов.