То, что вы испытываете, называется инициализация по умолчанию и правила для него (выделено мое):
- , если T не POD (доC ++ 11) Тип класса, конструкторы рассматриваются и подвергаются разрешению перегрузки против пустого списка аргументов.Выбранный конструктор (который является одним из конструкторов по умолчанию) вызывается для предоставления начального значения для нового объекта;
- , если T является типом массива, каждый элемент массива инициализируется по умолчанию;
- в противном случае ничего не делается: объекты с автоматической продолжительностью хранения (и их подобъекты) инициализируются неопределенными значениями.
Редактировать, вответ на запрос ОП ниже:
Обратите внимание, что объявление конструктора = default
не меняет ситуацию (опять-таки, выделено мое):
Неявно определенный конструктор по умолчанию
Если неявно объявленный конструктор по умолчанию не определен как удаленный, он определяется (то есть тело функции генерируется и компилируется) компилятором, если odr-используется, и имеет тот же эффект, что и пользовательский конструктор с пустым телом и пустым списком инициализатора .То есть он вызывает конструкторы по умолчанию для баз и нестатических членов этого класса.
Поскольку конструктор по умолчанию имеет пустой список инициализаторов, его члены удовлетворяют условиям дляИнициализация по умолчанию :
Инициализация по умолчанию выполняется в трех ситуациях:
...
3), когда базовый класс или нестатические данныеэлемент не упоминается в списке инициализатора конструктора, и этот конструктор вызывается.
Также обратите внимание, что вы должны быть осторожны при экспериментальном подтверждении этого, поскольку вполне возможно, что default-initialized значение int
может быть нулевым.В частности, вы упомянули, что это:
struct Foo {
Foo(){};
int member;
} foo;
В результате инициализация значения , но это не так;здесь member
инициализируется по умолчанию.
Редактировать 2:
Обратите внимание на следующее различие:
struct Foo {
int member;
};
Foo a; // is not value-initialized; value of `member` is undefined
Foo b = Foo(); // IS value-initialized; value of `member` is 0
Это поведение можно понятьследуя правилам инициализация значения :
Инициализация значения выполняется в следующих ситуациях:
1,5), когда безымянный временный объект создается синициализатор, состоящий из пустой пары скобок;
Форма 1 (T();
) - это форма, используемая в правой части =
выше для инициализации b
.
Эффект инициализации значения:
1) если T является типом класса без конструктора по умолчанию или с предоставленным пользователем или удаленным конструктором по умолчанию, объект инициализируется по умолчанию;
2) если T является типом класса с конструктором по умолчанию, который не предоставлен и не удален пользователем (то есть это может быть класс с неявно определенным или дефолтным конструктором по умолчанию), объект равен нулю-инициализирован, а затем деинициализируется с ошибкой, если он имеет нетривиальный конструктор по умолчанию;
3) если T является типом массива, каждый элемент массива инициализируется значением;
4) в противном случаеобъект инициализируется нулями.
Наконец, обратите внимание, что в нашем предыдущем примере:
struct Foo {
Foo(){}; // this satisfies condition (1) above
int member;
};
Foo f = Foo();
Теперь, условие (1) применяется, и наше (пусто) вместо этого вызывается объявленный пользователем конструктор.Поскольку этот конструктор не инициализирует member
, member
инициализируется по умолчанию (и, следовательно, его начальное значение не определено).