Рассмотрим следующий код:
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-квалифицированным) классом неединичного класса без конструктора, предоставленного пользователем, тогда объект инициализируется нулем и, еслиT
s неявно объявленный конструктор по умолчанию является нетривиальным, этот конструктор называется.- if
T
- тип массива, тогда каждый элемент инициализируется значением;- в противном случае объект инициализируется нулем.
Для нулевой инициализации объекта или ссылки типа T означает:
- если
T
- скалярный тип (3.9), объект устанавливается в значение0
(ноль), взятое как интегральное постоянное выражение, преобразованное вT
;- если
T
является (возможно, cv-квалифицированным) классом неединичного класса, каждый нестатический элемент данных и каждый подобъект базового класса инициализируются нулями, а заполнение инициализируется нулевыми битами;- Если
T
является (возможно, cv-квалифицированным) типом объединения, объекты первого нестатического именованного элемента данных инициализируются нулем, а заполнение инициализируется нулевыми битами;- если
T
- тип массива, каждый элемент инициализируется нулем;- Если
T
является ссылочным типом, инициализация не выполняется.
Здесь применяется вторая пуля.