Неинициализированные объекты существуют в С++?

Если все объекты имеют по крайней мере один конструктор, это по умолчанию c'tor, определяемый компилятором или пользователем, то как объекты могут быть неинициализированы.

Ответ 1

Можно объявлять объекты, на которых не выполняются инициализации. Эти объекты существуют, они имеют неопределенное значение, и использование этого значения - это поведение undefined (есть исключение из этого правила для символов).

Такой объект может быть создан по умолчанию. Это указано в стандарте С++ (§11.6 Инициализаторы) [dlc.init]:

Для инициализации объекта типа T по умолчанию:

(7.1) - Если T является классом класса (возможно, cv-qualit) (раздел 12), рассматриваются конструкторы. Применимое конструкторы перечислены (16.3.1.3), а лучший для инициализатора() выбирается посредством перегрузки резолюции (16.3). Выбранный таким образом конструктор вызывается с пустым списком аргументов для инициализации объект.

(7.2). Если T - тип массива, каждый элемент инициализируется по умолчанию.

(7.3) - В противном случае не выполняется инициализация.

Тем не менее, статические объекты всегда ноль-инициализируются. Таким образом, любой встроенный динамический или автоматический срок хранения не может быть инициализирован, даже если он является подзаголовком;

int i; //zero-initialized

struct A{
  int i;
  };

struct B
  {
  B(){};
   B(int i)
    :i{i}{}
  int i;
  int j;
  };
A a; //a.i is zero-initialized

int main()
  {
   int j;             //not initialized
   int k{};           //zero-initialized
   A b;               //b.i not initialized
   int* p = new int;  //*p not initialized
   A*   q = new A;    //q->i not initialized
   B ab;              //ab.i and ab.j not initialized
   B ab2{1};          //ab.j not initialized
   int xx[10];        //xx element not initialized.

   int l = i;    //OK l==0;
   int m = j;    //undefined behavior (because j is not initialized)
   int n = b.i;  //undefined behavior 
   int o = *p; //undefined behavior 
   int w = q->i; //undefined behavior 
   int ex = x[0] //undefined behavior
   }

Для инициализации члена [class.base.init] может помочь:

В конструкторе без делегирования, если данный потенциально сконструированный подобъект не обозначается mem- Инициализатор-идентификатор (включая случай, когда нет mem-initializer-list, поскольку у конструктора нет ctor-инициализатор), то - если объект является нестатическим членом данных, у которого есть инициализатор элемента по умолчанию (12.2) и либо

(9.1.1) - класс конструкторов является объединением (12.3), и никакой другой вариант член этого союза не обозначен с помощью mem-initializer-id или

(9.1.2) - класс конструкторов не является объединением и, если сущность является членом анонимного объединения, no другой член этого союза обозначается идентификатором mem-initializer-id, объект инициализируется из его инициализатора элемента по умолчанию, как указано в 11.6;

(9.2) - в противном случае, если объект является анонимным объединением или вариантом (12.3.1), никакая инициализация не является выполняется;

(9.3) - в противном случае объект инициализируется по умолчанию (11.6)

Члены тривиального анонимного объединения также не могут быть инициализированы.


Также можно было спросить, может ли жизнь жизни объекта начинаться без какой-либо инициализации, например, используя reinterpret_cast. Ответ следующий: reinterpret_cast, создающий тривиальный конструктивный объект по умолчанию

Ответ 2

В стандарте не говорится о существовании объектов, однако существует понятие времен жизни объектов.

В частности, из [basic.life]

Время жизни объекта типа T начинается, когда:

  • хранилище с правильным выравниванием и размером для типа T получено, а

  • если объект имеет непустую инициализацию, его инициализация завершена

С незапущенной инициализацией, определяемой как

Говорят, что объект имеет непустую инициализацию, если он относится к классу или aggregate type, и он или один из его подобъектов инициализируется конструктором, отличным от тривиального конструктора по умолчанию.

Мы можем заключить, что для объектов с пустыми инициализациями (например, int s) их сроки жизни начинаются сразу же после их хранения, даже если они оставлены неинициализированными.

void foo()
{
    int i;  // i lifetime begins after this line, but i is uninitialized
    // ...
}

† Добавлены ссылки для удобства чтения, они не отображаются в стандартном