По умолчанию, значение и нуль

Я очень смущен насчет инициализации значений и дефолтов и нулей. и особенно когда они пинают для разных стандартов С++ 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.

инициализатор:
&nbsp &nbsp &nbsp &nbsp скобка или равно-инициализатор
&nbsp &nbsp &nbsp &nbsp &nbsp (список выражений)
<Б > скобка или равно-инициализатор:
&nbsp &nbsp &nbsp = initializer-clause
&nbsp &nbsp &nbsp &nbsp braced-init-list
инициализатор-пункт:
&nbsp &nbsp &nbspassignment-expression
&nbsp &nbsp &nbsp &nbsp braced-init-list
<Б > инициализатор-лист:
&nbsp &nbsp &nbsp &nbsp initializer-clause... opt
&nbsp &nbsp &nbsp &nbsp список инициализаторов, initializer-clause... opt **
braced-init-list:
&nbsp &nbsp &nbsp &nbsp {initializer-list, opt}
&nbsp &nbsp &nbsp {}

Инициализация

Подобно С++ 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. Кроме того, Объект, Инициализатор - это пустой набор скобок, т.е.(), должен быть инициализирован значением