Совокупная безопасность инициализации в C++
Предположим, у меня есть следующая структура:
struct sampleData
{
int x;
int y;
};
И когда используется, я хочу инициализировать переменные sampleData
введите в известное состояние.
sampleData sample = { 1, 2 }
Позже я решаю, что мне нужны дополнительные данные, хранящиеся в моем sampleData
структура, следующим образом:
struct sampleData
{
int x;
int y;
int z;
};
Насколько я понимаю, инициализация двух полей осталась отz
структура данных по-прежнему является допустимым оператором и будет скомпилирована, заполняя недостающие поля значениями по умолчанию.
Это понимание правильно? Я недавно работал в Аде, которая также позволяет инициализировать агрегат, но которая помечает аналогичную проблему как ошибку компиляции. Если предположить, что мои предположения о приведенном выше коде C++ верны, существует ли языковая конструкция, которая распознает пропущенные значения инициализации как ошибку?
4 ответа
Инициализация переменных таким способом поддерживается только в Aggregate Classes.
Если вы добавите конструктор (-ы), тогда проблема исчезнет, но вам придется немного изменить синтаксис, и вы потеряете способность сохранять struct
в union
(между прочим).
struct sampleData
{
sampleData(int x, int y) : x(x), y(y) {}
int x;
int y;
};
sampleData sample( 1, 2 );
Добавление z
(и изменение конструктора) пометит sample( 1, 2 )
как ошибка компиляции.
Да, любые элементы, которые вы исключаете из списка инициализации, будут инициализированы нулем (для скалярных типов POD) или с использованием конструктора по умолчанию (для классов).
Соответствующий язык из стандарта C цитируется здесь:
[6.7.8.21] Если в списке, заключенном в фигурные скобки, меньше инициализаторов, чем элементов или членов агрегата или меньше символов в строковом литерале, используемом для инициализации массива известного размера, чем элементов в массиве, Остальная часть совокупности должна быть инициализирована неявно так же, как объекты, которые имеют статическую продолжительность хранения.
Я уверен, что кто-то более мотивированный, чем я мог найти соответствующий язык в одной из спецификаций C++...
Обратите внимание, что это означает, что скалярные элементы POD инициализируются так, как будто вы написали "= 0". Это означает, что он будет правильно инициализировать указатели в NULL и будет иметь значение 0.0, даже если их представления не будут равны нулю. Это также подразумевает, что это работает рекурсивно; если ваша структура содержит структуру, внутренняя структура также будет правильно инициализирована.
В качестве продолжения ответа Nemo со стандартом C, вот что говорит стандарт C++03:
§8.5.1 / 7:
Если в списке меньше инициализаторов, чем элементов в совокупности, то каждый элемент, не инициализированный явно, должен быть инициализирован значением.
§8.5 / 5:
Инициализировать значение объекта типа
T
средства:
- если
T
является типом класса с объявленным пользователем конструктором, тогда конструктор по умолчанию дляT
называется (и инициализация плохо сформирована, еслиT
не имеет доступного конструктора по умолчанию);- если
T
это тип класса без объединения без объявленного пользователем конструктора, тогда каждый нестатический член данных и компонент базового классаT
инициализируется значением;- если
T
тип массива, тогда каждый элемент инициализируется значением;- в противном случае объект инициализируется нулями
Для инициализации нуля объекта типа
T
средства:
- если
T
является скалярным типом, объект установлен в значение0
(ноль) преобразуется вT
;- если
T
является типом класса, не являющимся объединением, каждый нестатический элемент данных и каждый подобъект базового класса инициализируются нулями;- если
T
тип объединения, первый именованный элемент данных объекта) инициализируется нулями;- если
T
тип массива, каждый элемент инициализируется нулями;- если
T
является ссылочным типом, инициализация не выполняется.
Почему бы не использовать
sampleData sample = { x: 1, y:2 } ;
?
Но вы все равно столкнетесь с проблемой z
будучи инициализированным непредсказуемым значением, поэтому лучше определить конструктор, который устанавливает для всех переменных четко определенные значения.