По умолчанию, значение и нуль
Я очень смущен насчет инициализации значений и дефолтов и нулей.
и особенно когда они пинают для разных стандартов С++ 03 и С++ 11 (и С++ 14).
Я цитирую и пытаюсь продлить действительно хороший ответ Value-/Default-/Zero-Init С++ 98 и С++ 03, чтобы сделать это более общий, поскольку это помогло бы многим пользователям, если бы кто-то мог помочь заполнить необходимые пробелы, чтобы иметь хороший обзор о том, что происходит, когда?
Полное описание примеров в двух словах:
Иногда память, возвращаемая новым оператором, будет инициализирована, и иногда она не зависит от того, является ли тип, который вы новичок, POD (простые старые данные), или если это класс, содержащий элементы POD, и использует созданный компилятором конструктор по умолчанию.
- В С++ 1998 существует 2 типа инициализации: ноль и значение по умолчанию
- В С++ 2003 был добавлен третий тип инициализации, инициализация значения.
- В С++ 2011/С++ 2014 была добавлена только инициализация списка, а правила для инициализации value/default//zero немного изменились.
Предположим:
struct A { int m; };
struct B { ~B(); int m; };
struct C { C() : m(){}; ~C(); int m; };
struct D { D(){}; int m; };
struct E { E() = default; int m;} /** only possible in c++11/14 */
struct F {F(); int m;} F::F() = default; /** only possible in c++11/14 */
В компиляторе С++ 98 должно произойти следующее::
- новое значение A - неопределенное значение (A - POD)
- new A() - zero-initialize
- new B - конструкция по умолчанию (B:: m не инициализирована, B не является POD)
- new B() - конструкция по умолчанию (B:: m не инициализирована)
- новая конструкция C по умолчанию (C:: m инициализируется нулем, C не является POD)
- new C() - конструкция по умолчанию (C:: m инициализируется нулем)
- новый D - конструктор по умолчанию (D:: m не инициализирован, D не является POD)
- new D() - конструкцию по умолчанию? (D:: m не инициализируется)
В компиляторе, совместимом с С++ 03, все должно работать так:
- новое значение A - неопределенное значение (A - POD)
- new A() - инициализировать значение A, которое является нулевой инициализацией, поскольку это POD.
- new B - инициализирует по умолчанию (оставляет B:: m неинициализированным, B не является POD)
- new B() - значение инициализирует B, который нуль инициализирует все поля, поскольку его по умолчанию ctor генерируется компилятором в отличие от пользовательского.
- new C - default - инициализирует C, который вызывает значение по умолчанию ctor. (C:: m инициализируется нулем, C не является POD)
- new C() - значение инициализирует C, который вызывает значение по умолчанию ctor. (C:: m инициализируется нулем)
- новый D - конструктор по умолчанию (D:: m не инициализирован, D не является POD)
- new D() - значение инициализирует D?, который вызывает значение по умолчанию ctor (D:: m не инициализируется)
Курсивные значения и? являются неопределенностями, пожалуйста, помогите исправить это: -)
В компиляторе, совместимом с С++ 11, все должно работать так:
??? (пожалуйста, помогите, если я начну здесь, это все равно пойдет не так)
В компиляторе, совместимом с С++ 14, все должно работать так:
??? (пожалуйста, помогите, если я начну здесь, это все равно пойдет не так)
(Проект основан на ответе)
- new A - default - инициализирует A, компилятор gen. ctor, (leavs A:: m неинициализирован) (A - POD)
-
new A() - значение инициализирует A, который является нулевой инициализацией, поскольку 2. point in [dcl.init]/8
-
new B - по умолчанию инициализирует B, компилятор gen. ctor, (leavs A:: m неинициализирован) (B не является POD)
- new B() - значение инициализирует B, который нуль инициализирует все поля, поскольку его по умолчанию ctor генерируется компилятором в отличие от пользовательского.
- new C - default - инициализирует C, который вызывает значение по умолчанию ctor. (C:: m инициализируется нулем, C не является POD)
- new C() - значение инициализирует C, который вызывает значение по умолчанию ctor. (C:: m инициализируется нулем)
- new D - инициализация по умолчанию D (D:: m не инициализируется, D не является POD)
- new D() - значение инициализирует D, который вызывает значение по умолчанию ctor (D:: m не инициализируется)
- new E - default - инициализирует E, который вызывает comp. поколения. т е р. (D:: m не инициализируется, D не является POD)
- new E() - значение инициализирует E, который нуль инициализирует E, поскольку 2 точки в [dcl.init]/8)
- new F - default - инициализирует F, который вызывает comp. поколения. т е р. (D:: m не инициализируется, D не является POD)
- new F() - значение инициализирует F, который по умолчанию инициализирует F с 1. point в [dcl.init]/8 (функция предоставляется пользователем, если она объявлена пользователем и явно не дефолты или не удалены по его первой декларации. Ссылка)
Ответы
Ответ 1
С++ 14 указывает инициализацию объектов, созданных с помощью new
в [expr.new]/17 ([expr.new]/15 в С++ 11, и примечание не было примечанием, но нормативный текст назад затем):
Новое выражение, создающее объект типа T
, инициализирует это объект следующим образом:
- Если новый инициализатор опущен, объект инициализируется по умолчанию (8.5). [Примечание: если инициализация отсутствует выполняется, объект имеет неопределенное значение. - конечная нота]
- В противном случае новый-инициализатор интерпретируется в соответствии с правилами инициализации 8.5 для прямой инициализации.
Инициализация по умолчанию определена в [dcl.init]/7 (/6 в С++ 11, и сама формулировка имеет тот же эффект):
Для инициализации объекта типа T
по умолчанию:
- Если
T
является (возможно, cv-квалифицированным) типом класса (раздел 9), вызывается конструктор по умолчанию (12.1) для T
(и инициализация плохо сформирован, если T
не имеет конструктора по умолчанию или разрешения перегрузки (13.3) приводит к двусмысленности или в функции, которая удалена или недоступный из контекста инициализации); - if
T
- тип массива, каждый элемент инициализируется по умолчанию; - в противном случае инициализация не выполняется.
Таким образом,
-
new A
вызывает только конструктор по умолчанию A
по умолчанию, который не инициализирует m
. Неопределенное значение. Должно быть одинаковым для new B
.
-
new A()
интерпретируется в соответствии с [dcl.init]/11 (/10 в С++ 11):
Объект, инициализатор которого представляет собой пустой набор скобок, т.е. ()
, должен инициализироваться значением.
А теперь рассмотрим [dcl.init]/8 (/7 в С++ 11 †):
Для инициализации значения объекта типа T
означает:
- если
T
является (возможно, cv-квалифицированным) типом класса (раздел 9) без конструктора по умолчанию (12.1) или конструктора по умолчанию, который предоставляемый пользователем или удаленный, то объект инициализируется по умолчанию; - , если
T
является (возможно, cv-qualit) типом класса без предоставленного пользователем или удаляемого конструктора по умолчанию, тогда объект нулевой инициализации и семантические ограничения для проверяется инициализация по умолчанию, и если T имеет нетривиальное значение по умолчанию конструктор, объект инициализируется по умолчанию; - Если
T
- тип массива, то каждый элемент инициализируется значением; - в противном случае объект инициализируется нулем.
Следовательно, new A()
будет инициализироваться нулем m
. И это должно быть эквивалентно для A
и B
.
-
new C
и new C()
будет по умолчанию инициализировать объект снова, поскольку применяется первая маркерная точка из последней кавычки (C имеет предоставленный пользователем конструктор по умолчанию!). Но, очевидно, теперь m
инициализируется в конструкторе в обоих случаях.
† Ну, этот параграф имеет немного другую формулировку в С++ 11, которая не изменяет результат:
Для инициализации значения объекта типа T
означает:
- если
T
является (возможно, cv-квалифицированным) классом (раздел 9) с предоставленный пользователем конструктор (12.1), тогда конструктор по умолчанию для T
(и инициализация плохо сформирована, если T не имеет доступного конструктор по умолчанию); - если
T
является (возможно, cv-квалифицированным) неединичным тип класса без созданного пользователем конструктора, тогда объект нуль-инициализирован и, если T
s неявно объявленный конструктор по умолчанию является нетривиальным, этот конструктор называется. - if
T
- тип массива, то каждый элемент инициализируется значением; - в противном случае объект нулевой инициализируется.
Ответ 2
Следующий ответ расширяет ответ fooobar.com/info/72/..., который будет служить ссылкой для С++ 98 и С++ 03
Цитирование ответа
- В С++ 1998 существует 2 типа инициализации: ноль и значение по умолчанию
- В С++ 2003 инициализация 3-го типа, инициализация значения была
добавлен.
С++ 11 (ссылка на n3242)
Инициализаторы
8.5 Инициализаторы [dcl.init] указывают, что переменная POD или non POD может быть инициализирована либо как скопированный или равный-инициализатор, который может быть либо бит-init-list, либо initializer-clause, агрегированный как скобка-или -equal-initializer или используя (список-выражение). Ранее на С++ 11 поддерживался только (список выражений) или предложение initializer, хотя предложение initializer было более ограниченным, чем то, что мы имеем в С++ 11. В С++ 11 предложение initializer теперь поддерживает бит-init-list, кроме выражения-назначения, как это было в С++ 03. Следующая грамматика суммирует новое поддерживаемое предложение, где эта часть выделена жирным шрифтом, добавлена в стандарт С++ 11.
инициализатор:
        скобка или равно-инициализатор
          (список выражений)
<Б > скобка или равно-инициализатор:
      = initializer-clause
        braced-init-list
инициализатор-пункт:
     assignment-expression
        braced-init-list
<Б > инициализатор-лист:
        initializer-clause... opt
        список инициализаторов, initializer-clause... opt **
braced-init-list:
        {initializer-list, opt}
      {}
Инициализация
Подобно С++ 03, С++ 11 по-прежнему поддерживает три формы инициализации
Примечание
Часть, выделенная полужирным шрифтом, была добавлена в С++ 11, а тот, который вычеркнут, был удален из С++ 11.
-
Тип инициализатора: 8.5.5 [dcl.init] _zero-initialize_
Выполняется в следующих случаях
- Объекты со статическим или потоковым хранилищем ноль инициализируются
- Если число инициализаторов меньше, чем элементов массива, каждый элемент, явно не инициализированный, должен быть инициализирован нулем
- Во время инициализации значения, если T является (возможно, cv-квалифицированным) классом типа non-union без предоставленного пользователем конструктора, тогда объект инициализируется нулем.
Для нулевой инициализации объекта или ссылки типа T означает:
- если T - скалярный тип (3.9), объект устанавливается в значение 0 (ноль), , взятое как интегральное выражение константы, преобразованное в T;
- если T является классом (возможно, cv-qualit), не являющимся единственным классом, каждый нестатический элемент данных и каждый подобъект базового класса инициализируются нулями , а заполнение инициализируется нулевые биты;
- если T - тип объединения (возможно, cv-квалифицированный), объекты первого нестатического именованного элемента данных ноль инициализируются , а заполнение инициализируется нулевыми битами;
- если T - тип массива, каждый элемент инициализируется нулем;
- если T является ссылочным типом, инициализация не выполняется.
2. Тип инициализатора: 8.5.6 [dcl.init] _default-initialize _
Выполняется в следующих случаях
- Если новый инициализатор опущен, объект инициализируется по умолчанию; если инициализация не выполняется, объект имеет неопределенное значение.
- Если для объекта не задан инициализатор, объект инициализируется по умолчанию, за исключением объектов со статикой или продолжительностью хранения потоков
- Когда базовый класс или нестатический элемент данных не упоминается в списке инициализатора конструктора и этот конструктор вызывается.
Для инициализации объекта типа T по умолчанию:
- если T является классом (возможно, cv-qualified)
не-POD (раздел 9), вызывается конструктор по умолчанию для T (и инициализация плохо -формат, если T не имеет доступного конструктора по умолчанию); - если T - тип массива, каждый элемент инициализируется по умолчанию;
- в противном случае инициализация не выполняется.
ПримечаниеДо С++ 11 только типы классов, отличных от POD, с автоматической продолжительностью хранения считались инициализированными по умолчанию, когда не использовался инициализатор.
3. Тип инициализатора: 8.5.7 [dcl.init] _value-initialize _
- Когда объект (именная временная, именованная переменная, динамическая память или нестатический элемент данных), инициатор которой представляет собой пустой набор круглых скобок, т.е.() или фигурных скобок {}
Для инициализации объекта типа типа T означает:
- если T является классом (возможно, cv-qualified) (раздел 9) с предоставленным пользователем конструктором (12.1), тогда вызывается конструктор по умолчанию для T (и инициализация плохо если у T нет доступных конструктор по умолчанию);
- если T является (возможно, cv-квалифицированным) классом типа non-union без предоставленного пользователем конструктора,
, то каждый нестатический элемент данных и компонент базового класса T инициализируются значением; , тогда объект инициализируется нулем и, если Ts неявно объявленный конструктор по умолчанию является нетривиальным, этот конструктор вызывается. - если T - тип массива, то каждый элемент инициализируется значением;
- в противном случае объект инициализируется нулем.
Итак, чтобы подвести итоги
Примечание Соответствующая цитата из стандарта выделена в жирным шрифтом
- new A: default-initializes (оставляет A:: m неинициализированным)
- new A(): Zero-initialize A, поскольку инициализируемый значением кандидат не имеет предоставленного пользователем или удаленного конструктора по умолчанию. , если T является (возможно, cv-квалифицированным) классом типа non-union без конструктора, предоставленного пользователем, тогда объект инициализируется нулем и, если TS неявно объявленный конструктор по умолчанию является нетривиальным, этот конструктор называется.
- new B: default-initializes (оставляет B:: m неинициализированным)
- new B(): значение-инициализирует B, который нуль инициализирует все поля; , если T - тип класса (возможно, cv-qualit) (раздел 9) с предоставленным пользователем конструктором (12.1), тогда конструктор по умолчанию для T называется
- new C: default - инициализирует C, который вызывает значение по умолчанию ctor. , если T является классом класса (возможно, cv-qualit) (раздел 9), конструктор по умолчанию для T называется. Кроме того, если новый инициализатор опущен, объект инициализируется по умолчанию
- new C(): значение инициализирует C, который вызывает значение по умолчанию ctor. , если T - тип класса (возможно, cv-qualit) (раздел 9) с предоставленным пользователем конструктором (12.1), тогда вызывается конструктор по умолчанию для T. Кроме того, Объект, Инициализатор - это пустой набор скобок, т.е.(), должен быть инициализирован значением