- Компилятор автоматически генерирует конструктор по умолчанию?
- Неявно ли сгенерированный конструктор по умолчанию выполняет ноль
инициализация
Если вы законно анализируете язык стандарта 2003 года, то ответы будут: да и нет . Однако это не вся история , поскольку в отличие от определяемого пользователем конструктора по умолчанию, неявно определенный конструктор по умолчанию не всегда используется при создании объекта с нуля - существует два другие сценарии: без построения и инициализация значения по элементам .
Случай "без конструкции" на самом деле просто техническая, потому что он функционально не отличается от вызова тривиального конструктора по умолчанию. Другой случай более интересен: инициализация значений по элементам вызывается с помощью "()" [как если бы он явно вызывал конструктор без аргументов] и обходит то, что технически называется 1027 * конструктор по умолчанию . Вместо этого он рекурсивно выполняет инициализацию значения для каждого элемента данных, а для примитивных типов данных это в конечном итоге приводит к инициализации нуля .
Таким образом, компилятор предоставляет два разных неявно определенных конструктора по умолчанию . Один из которых выполняет инициализацию данных примитивного элемента нулем, а другой - нет. Вот несколько примеров того, как вы можете вызывать каждый тип конструктора:
MyClass a; // default-construction or no construction
MyClass b = MyClass(); // member-wise value-initialization
и
new MyClass; // default-construction or no construction
new MyClass(); // member-wise value-initialization
Примечание. Если объявленный пользователем конструктор по умолчанию существует , тогда для инициализации значения по элементу просто вызывается и останавливается.
Вот несколько подробное описание того, что стандарт говорит об этом ...
Если вы не объявляете конструктор, компилятор неявно создает конструктор по умолчанию [12.1-5]
Конструктор по умолчанию не инициализирует типы примитивов [12.1-7]
MyClass() {} // implicitly defined constructor
Если вы инициализируете объект с помощью «()», это напрямую не вызывает конструктор по умолчанию. Вместо этого он запускает длинную последовательность правил, которая называется значение-инициализация [8.5-7]
Чистый эффект инициализации значения заключается в том, что неявно объявленный конструктор по умолчанию никогда не вызывается . Вместо этого вызывается рекурсивная инициализация значений элементов, которая в конечном итоге инициализирует нулями любые примитивные элементы и вызывает конструктор по умолчанию для любых элементов, которые имеют объявленный пользователем конструктор [8.5-5]
Инициализация значений применяется даже к примитивным типам - они будут инициализироваться нулями. [8.5-5]
a = int(); // equivalent to int a=0;
Все это действительно спорный вопрос для большинства целей. Создатель класса обычно не может предполагать, что члены данных будут обнулены во время неявной последовательности инициализации - поэтому любой самоуправляемый класс должен определить свой собственный конструктор, если у него есть какие-либо примитивные члены данных, которые требуют инициализации.
Так, когда это имеет значение?
Могут быть обстоятельства, когда универсальный код хочет принудительно инициализировать неизвестные типы. Инициализация значения обеспечивает способ сделать это. Просто помните, что неявная инициализация нуля не происходит, если пользователь предоставил конструктор.
По умолчанию данные, содержащиеся в std :: vector, инициализируются значением. Это может помешать отладчикам памяти идентифицировать логические ошибки, связанные с неинициализированными буферами памяти.
vector::resize( size_type sz, T c=T() ); // default c is "value-initialized"
Целые массивы типа примитивов или структур типа "plain-old-data" (POD) могут быть инициализированы нулями с использованием синтаксиса инициализации значения.
new int[100]();
Этот пост содержит более подробную информацию о различиях между версиями стандарта, а также отмечает случай, когда стандарт применяется по-разному в основных компиляторах.