Инициализация члена по умолчанию C++ и конструкторы

Я хотел бы знать, где я могу найти документацию о следующем поведении:

class Foo {
public:
  Foo(int argX) : Foo(argX, defaultYValue) {}
  Foo(int argX, int argY) : x(argX), y(argY) {};
private:
  const int x;
  const int y;
  const int defaultYValue = -1;
}

Возможно ли, что значение y не определено? Или в стандарте есть какая-то документация, в которой говорится, что это работает (я заметил, что инициализация члена по умолчанию отбрасывается, если она иным образом переопределяется внутри конструктора)

PS: это было обнаружено, когда я забыл о статике для defaultYValue.

В каком случае x не будет инициализирован? Возможно, вы хотели спросить о y, значение которого зависит от defaultYValue в первом конструкторе?

UnholySheep 17.05.2022 15:29

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

Vincent Le Ligeour 17.05.2022 15:33

Конструкторы должны инициализировать все члены данных, которые не имеют значений по умолчанию. Вы спрашиваете о : Foo(argX, defaultYValue)? Это отлично работает, это называется делегирующий конструктор, документ: en.cppreference.com/w/cpp/язык/конструктор

Oasin 17.05.2022 15:37

Сводится к вопросу, когда эти значения по умолчанию действительно инициализируются... Поскольку -i-s- была первой объявленной переменной, она будет инициализирована первой, однако есть некоторые сомнения, что это произойдет до делегирования другому конструктору, поэтому Я бы сказал, что предполагать вы действительно читаете неинициализированное значение — даже до ваше редактирование...

Aconcagua 17.05.2022 15:38

@Oasin Я предполагаю, что понятно, что мы говорим о делегировании конструктора — однако проблема в том, что значение, которое нужно инициализировать, передается в качестве аргумента делегированному конструктору — и теперь возникает вопрос: передаем ли мы неинициализированное значение последнему или нет? ??

Aconcagua 17.05.2022 15:41

За поведением можно наблюдать и играть здесь: onlinegdb.com/_q7Q6Xmbv

Vincent Le Ligeour 17.05.2022 15:47

Даже для вопроса неотредактированный: onlinegdb.com/ttrgUM_Wx...

Aconcagua 17.05.2022 15:50

Будет ли это работать со статическим или constexpr defaultYValue?

Sebastian 17.05.2022 15:52
Формы c голосовым вводом в React с помощью Speechly
Формы c голосовым вводом в React с помощью Speechly
Пытались ли вы когда-нибудь заполнить веб-форму в области электронной коммерции, которая требует много кликов и выбора? Вас попросят заполнить дату,...
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Будучи разработчиком веб-приложений, легко впасть в заблуждение, считая, что приложение без JavaScript не имеет права на жизнь. Нам становится удобно...
Flatpickr: простой модуль календаря для вашего приложения на React
Flatpickr: простой модуль календаря для вашего приложения на React
Если вы ищете пакет для быстрой интеграции календаря с выбором даты в ваше приложения, то библиотека Flatpickr отлично справится с этой задачей....
В чем разница между Promise и Observable?
В чем разница между Promise и Observable?
Разберитесь в этом вопросе, и вы значительно повысите уровень своей компетенции.
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Клиент для URL-адресов, cURL, позволяет взаимодействовать с множеством различных серверов по множеству различных протоколов с синтаксисом URL.
Четыре эффективных способа центрирования блочных элементов в CSS
Четыре эффективных способа центрирования блочных элементов в CSS
У каждого из нас бывали случаи, когда нам нужно отцентрировать блочный элемент, но мы не знаем, как это сделать. Даже если мы реализуем какой-то...
7
8
164
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Да, код имеет неопределенное поведение. При использовании делегирующий конструктор именно делегирующий конструктор инициализирует члены класса. Когда вы передаете defaultYValue конструктору делегирования, он еще не инициализирован, поэтому вы передаете неинициализированное значение делегату, и указанный делегат использует это значение для установки y.

Это вызвано [класс.base.инит]/7

The expression-list or braced-init-list in a mem-initializer is used to initialize the designated subobject (or, in the case of a delegating constructor, the complete class object) according to the initialization rules of [dcl.init] for direct-initialization.

I would like to know where I can find some documentation about the following behavior:

Это называется делегация, а конструктор Foo::Foo(int) называется делегирующий конструктор.

Из класс.base.init-6

A mem-initializer-list can delegate to another constructor of the constructor's class using any class-or-decltype that denotes the constructor's class itself. If a mem-initializer-id designates the constructor's class, it shall be the only mem-initializer; the constructor is a delegating constructor, and the constructor selected by the mem-initializer is the target constructor. The target constructor is selected by overload resolution. Once the target constructor returns, the body of the delegating constructor is executed. If a constructor delegates to itself directly or indirectly, the program is ill-formed, no diagnostic required.


Might it be possible that y value is undefined ?

Да, программа имеет неопределенное поведение.

От класс.base.init-7:

The expression-list or braced-init-list in a mem-initializer is used to initialize the designated subobject (or, in the case of a delegating constructor, the complete class object) according to the initialization rules of [dcl.init] for direct-initialization.

Это означает, что целевой конструкторFoo::Foo(int, int) используется для инициализации элементов данных. Но поскольку вы передаете член данных defaultYValue, который еще не инициализирован, у нас неопределенное поведение.

Как указано в других ответах, во время использования defaultYValue оно еще не было инициализировано. Вы можете исправить это, сделав его satic:

class Foo {
public:
  Foo(int argX) : Foo(argX, Foo::defaultYValue) {}
  Foo(int argX, int argY) : x(argX), y(argY) {};
private:
  const int x;
  const int y;
  static const int defaultYValue = -1;
}

Но никогда не пишите 2 конструктора, если достаточно одного:

class Foo {
public:
  Foo(int argX, int argY = defaultYValue) : x(argX), y(argY) {};
private:
  const int x;
  const int y;
  static const int defaultYValue = -1;
}

Но на самом деле зачем определять константу, если она используется только один раз? Из использования ясно, что это значение по умолчанию для y. Никакой дополнительной информации, полученной от его названия defaultYValue, не получено:

class Foo {
public:
  Foo(int argX, int argY = -1) : x(argX), y(argY) {};
private:
  const int x;
  const int y;
}

В контексте это должны быть имена, чтобы дать больше контекста тому, что это такое, и значение должно принадлежать классу, потому что это частная реализация какого-то странного поведения. В целом я не большой поклонник наличия значений по умолчанию в определении метода/конструктора, я предпочитаю быть явным (это помогло мне несколько раз при выполнении рефакторинга всегда иметь обязательные параметры, также легче найти ссылку на конкретный вызов конструктора в вашей IDE.

Vincent Le Ligeour 17.05.2022 16:10

Тогда используйте static const int, enum или enum class.

Goswin von Brederlow 17.05.2022 16:12

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

Vincent Le Ligeour 17.05.2022 16:14

Другие вопросы по теме