Какую проблему это решает, что для не пустых инициализации время жизни начинается до инициализации? - PullRequest
0 голосов
/ 04 сентября 2018

В текущем проекте стандарта (предыдущие стандарты имеют похожую формулировку) в [basic.life/1] :

Время жизни объекта или ссылки - это свойство времени выполнения объекта или ссылки. Говорят, что объект имеет не пустую инициализацию, если он имеет класс или агрегатный тип, и он или один из его подобъектов инициализируются конструктором, отличным от тривиального конструктора по умолчанию. [Примечание: инициализация тривиальным конструктором копирования / перемещения - это не пустая инициализация. - примечание конца] Время жизни объекта типа T начинается, когда:

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

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

Почему здесь важно, чтобы инициализация была не пустая ? Другими словами, почему время жизни начинается до завершения инициализации, если инициализация не не пустая ? Какую проблему это решает?

Каковы будут последствия, если (1.2) будет читаться как

(1.2) если объект имеет инициализацию, его инициализация завершена

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


Обратите внимание, у меня был похожий предыдущий вопрос здесь , но, поскольку этот вопрос немного слишком широк (и даже я принял один из ответов), ответы там не отвечают на этот вопрос текущий вопрос.

Ответы [ 3 ]

0 голосов
/ 04 сентября 2018

Я думаю, что он предназначен для обхода инициализации по умолчанию, которая не выполняет инициализацию:

[dlc.init]:

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

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

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

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

Я понимаю, что все объекты имеют инициализацию, но для некоторых объектов с инициализацией по умолчанию инициализация не выполняется. Обратите внимание, что в нем конкретно сказано, что « инициализация не выполняется », а не то, что она не существует.

У вас может быть инициализированный по умолчанию объект, для которого инициализация не была выполнена, поэтому он не может завершиться. Они не будут начинать свою жизнь, и с текущей формулировкой им не нужно ждать, пока это не начнется, для их начала. Также такой объект должен иметь инициализацию, потому что он инициализирован по умолчанию.

ИМХО, ваша формулировка будет иметь ошибку, или вы понимаете, что это вызовет логические последствия для 7.3 определения по умолчанию для инициализации, потому что такие объекты будут либо:

  1. Инициализировать и не начинать жить, потому что это не было выполнено.
  2. Инициализируется по умолчанию, но не будет инициализироваться. Я понимаю, что это может сбить с толку.

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

0 голосов
/ 04 сентября 2018

Разница между стандартной цитатой, включающей определение «незаполненной инициализации», и вашим альтернативным предложением без «непустой» заключается в том, что стандартное предложение допускает некоторые случаи, когда время жизни объекта начинается до завершения его инициализации.

Существует три способа (я могу подумать), что объект может быть использован до завершения его инициализации:

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

  2. Имя объекта используется в его собственном инициализаторе.

  3. Доступ к объекту осуществляется через this (возможно, неявный) в конструкторе.

# 2 необычен, и # 3 здесь всегда исключается как незаполненная инициализация, поэтому давайте посмотрим на # 1. # 1 - это точная установка для статического порядка инициализации Fiasco, но, согласно «непустой» формулировке, Стандарт говорит, что некоторые из этих случаев на самом деле хороши:

int f();
int n = f();
int a[3] = {f(), f(), f()};
struct X {};
struct Y { int p; int q[2]; X x; };
Y y = { f(), { f(), f() }, {} };

Здесь все объявленные объекты имеют как нулевую инициализацию, так и динамическую инициализацию. Их можно использовать во время динамической инициализации другого объекта со статической продолжительностью хранения, определенной ранее в той же единице перевода (или во время их собственных инициализаторов), поскольку их время жизни уже началось, и значения всех int объектов будут равны нулю. Они могут использоваться во время динамической инициализации объекта, определенного в другой единице перевода, и поведение не определено, а не неопределенно, при этом значения int равны нулю или возвращают значение соответствующего выражения f().

0 голосов
/ 04 сентября 2018

Например,

int i = i;

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


Еще один несколько содержательный пример:

struct A {
    int i, j;
    int square()
    {
        return i * i;
    }
};

A a{0, a.square()}; 

Это четко определено. Без «непустого» ограничения это было бы неопределенным, потому что a используется для вызова нестатической функции-члена до того, как начинается время жизни a.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...