Рассмотрим следующий код:
class A {
public:
int i;
A() {}
};
class B {
public:
A a;
int i;
};
int main() {
B* p = new B {};
std::cout << p->i << " " << p->a.i << "\n";
}
Скомпилированный с -std = С++ 11 в clang++, p->i оказывается равным нулю, но p->a.i этого не делает. Не следует ли обнулить весь объект до тех пор, пока его класс не имеет конструктора, предоставленного пользователем?
EDIT: Поскольку в комментариях есть несколько подробных обсуждений, я думаю, что лучше добавить некоторые выдержки из стандарта здесь:
Для инициализации значения объекта типа
Tозначает:
- Если
Tявляется (возможно, cv-qualit) типом класса (раздел 9) с предоставленным пользователем конструктором (12.1), тогда вызывается конструктор по умолчанию для T (и инициализация плохо сформирована, еслиTне имеет доступного конструктора по умолчанию);- если
Tявляется (возможно, cv-квалифицированным) классом неединичного класса без конструктора, предоставленного пользователем, тогда объект инициализируется нулем и, еслиTs неявно объявленный конструктор по умолчанию является нетривиальным, этот конструктор называется.- if
T- тип массива, тогда каждый элемент инициализируется значением;- в противном случае объект инициализируется нулем.
Для нулевой инициализации объекта или ссылки типа T означает:
- если
T- скалярный тип (3.9), объект устанавливается в значение0(ноль), взятое как интегральное постоянное выражение, преобразованное вT;- если
Tявляется (возможно, cv-квалифицированным) классом неединичного класса, каждый нестатический элемент данных и каждый подобъект базового класса инициализируются нулями, а заполнение инициализируется нулевыми битами;- Если
Tявляется (возможно, cv-квалифицированным) типом объединения, объекты первого нестатического именованного элемента данных инициализируются нулем, а заполнение инициализируется нулевыми битами;- если
T- тип массива, каждый элемент инициализируется нулем;- Если
Tявляется ссылочным типом, инициализация не выполняется.
Здесь применяется вторая пуля.