Какую форму принимает неявно объявленный конструктор по умолчанию? - PullRequest
0 голосов
/ 30 мая 2018

Допустим, я работаю с этим игрушечным примером:

struct Foo {
    int member;
};

Я знаю, что конструктор по умолчанию не будет инициализировать по умолчанию member.Поэтому, если я сделаю это, member останется неинициализированным: const Foo implicit_construction. Кроме того, это, кажется, работает нормально: const Foo value_initialization = Foo() хотя я понимаю, что на самом деле это не использует конструктор по умолчанию.

Если я изменю Foo следующим образом:

struct Foo {
    Foo() = default;
    int member;
};

И я пытаюсь сделать const Foo defaulted_construction, что неудивительно, что он ведет себя точно так же, как implicit_construction, с member неинициализированным.

Наконец, если я изменю Foo на это:

struct Foo {
    Foo(){};
    int member;
};

И я делаю: const Foo defined_construction member с нулевой инициализацией.Я просто пытаюсь понять, как выглядит неявно определенный конструктор.Хотелось бы, чтобы это было Foo(){}.Разве это не так?Есть ли какая-то другая черная магия, которая заставляет мой определенный конструктор вести себя иначе, чем дефолтный?


Редактировать:

Возможно, меня вводят в заблуждение,defaulted_construction определенно неинициализирован .
Хотя defined_construction определенно инициализирован .

Я принял это за стандартизированное поведение, это неправильно?

1 Ответ

0 голосов
/ 30 мая 2018

То, что вы испытываете, называется инициализация по умолчанию и правила для него (выделено мое):

  • , если T не POD (доC ++ 11) Тип класса, конструкторы рассматриваются и подвергаются разрешению перегрузки против пустого списка аргументов.Выбранный конструктор (который является одним из конструкторов по умолчанию) вызывается для предоставления начального значения для нового объекта;
  • , если T является типом массива, каждый элемент массива инициализируется по умолчанию;
  • в противном случае ничего не делается: объекты с автоматической продолжительностью хранения (и их подобъекты) инициализируются неопределенными значениями.

Редактировать, вответ на запрос ОП ниже:

Обратите внимание, что объявление конструктора = default не меняет ситуацию (опять-таки, выделено мое):

Неявно определенный конструктор по умолчанию

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

Поскольку конструктор по умолчанию имеет пустой список инициализаторов, его члены удовлетворяют условиям дляИнициализация по умолчанию :

Инициализация по умолчанию выполняется в трех ситуациях:

...

3), когда базовый класс или нестатические данныеэлемент не упоминается в списке инициализатора конструктора, и этот конструктор вызывается.

Также обратите внимание, что вы должны быть осторожны при экспериментальном подтверждении этого, поскольку вполне возможно, что default-initialized значение int может быть нулевым.В частности, вы упомянули, что это:

struct Foo {
    Foo(){};
    int member;
} foo;

В результате инициализация значения , но это не так;здесь member инициализируется по умолчанию.

Редактировать 2:

Обратите внимание на следующее различие:

struct Foo {
    int member;
};

Foo a; // is not value-initialized; value of `member` is undefined
Foo b = Foo(); // IS value-initialized; value of `member` is 0

Это поведение можно понятьследуя правилам инициализация значения :

Инициализация значения выполняется в следующих ситуациях:

1,5), когда безымянный временный объект создается синициализатор, состоящий из пустой пары скобок;

Форма 1 (T();) - это форма, используемая в правой части = выше для инициализации b.

Эффект инициализации значения:

1) если T является типом класса без конструктора по умолчанию или с предоставленным пользователем или удаленным конструктором по умолчанию, объект инициализируется по умолчанию;

2) если T является типом класса с конструктором по умолчанию, который не предоставлен и не удален пользователем (то есть это может быть класс с неявно определенным или дефолтным конструктором по умолчанию), объект равен нулю-инициализирован, а затем деинициализируется с ошибкой, если он имеет нетривиальный конструктор по умолчанию;

3) если T является типом массива, каждый элемент массива инициализируется значением;

4) в противном случаеобъект инициализируется нулями.

Наконец, обратите внимание, что в нашем предыдущем примере:

struct Foo {
    Foo(){}; // this satisfies condition (1) above
    int member;
};

Foo f = Foo();

Теперь, условие (1) применяется, и наше (пусто) вместо этого вызывается объявленный пользователем конструктор.Поскольку этот конструктор не инициализирует member, member инициализируется по умолчанию (и, следовательно, его начальное значение не определено).

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