Можно ли инициализировать структуры в C ++, как указано ниже
struct address {
int street_no;
char *street_name;
char *city;
char *prov;
char *postal_code;
};
address temp_address =
{ .city = "Hamilton", .prov = "Ontario" };
Ссылки здесь и здесь упоминают, что этот стиль можно использовать только в C. Если это так, то почему это невозможно в C ++? Есть ли какая-либо техническая причина, почему он не реализован в C ++, или это плохая практика использовать этот стиль. Мне нравится использовать этот способ инициализации, потому что моя структура большая, и этот стиль дает мне четкую читаемость того, какое значение назначено какому члену.
Пожалуйста, поделитесь со мной, если есть другие способы, с помощью которых мы можем достичь той же читабельности.
Я ссылался на следующие ссылки, прежде чем отправлять этот вопрос
Ответы:
Если вы хотите прояснить, что представляет собой каждое значение инициализатора, просто разбейте его на несколько строк с комментарием к каждой:
источник
char*
), что и один из других членов выше или ниже в структуре, потому что нет риска поменять их местами.(struct timeval){ .seconds = 0, .microseconds = 100 }
всегда будет сто микросекунд, ноtimeval { 0, 100 }
может быть сто секунд . Вы не хотите найти что-то подобное на своем пути.После того, как мой вопрос не привел к удовлетворительному результату (потому что C ++ не реализует основанный на тегах init для структур), я взял трюк, который нашел здесь: члены структуры C ++ инициализируются в 0 по умолчанию?
Для вас это составит:
Это, безусловно, ближе всего к тому, что вы хотели изначально (обнулите все поля, кроме тех, которые вы хотите инициализировать).
источник
static address temp_address = {};
буду работать. Заполнение его потом зависит от времени выполнения, да. Вы можете обойти это, предоставляя функцию статической , которая делает инициализации для вас:static address temp_address = init_my_temp_address();
.init_my_temp_address
может быть лямбда-функция:static address temp_address = [] () { /* initialization code */ }();
address
и вы никогда не узнаете обо всех местах, в которых он создан,address
и теперь не инициализируйте своего нового участника.Как уже упоминали другие, это обозначается как инициализатор.
Эта функция является частью C ++ 20
источник
Идентификаторы полей действительно являются синтаксисом инициализатора Си. В C ++ просто дайте значения в правильном порядке без имен полей. К сожалению, это означает, что вам нужно дать их все (на самом деле вы можете не указывать конечные поля с нулевым значением, и результат будет таким же):
источник
Эта функция называется назначенными инициализаторами . Это дополнение к стандарту C99. Однако эта функция была исключена из C ++ 11. В соответствии с языком программирования C ++, 4-е издание, раздел 44.3.3.2 (функции C, не принятые в C ++):
Грамматика C99 имеет обозначенные инициализаторы [См. ИСО / МЭК 9899: 2011, Проект комитета N1570 - 12 апреля 2011 г.]
6.7.9 Инициализация
С другой стороны, C ++ 11 не имеет обозначенных инициализаторов [См. ИСО / МЭК 14882: 2011, Проект комитета N3690 - 15 мая 2013 г.]
8.5 Инициализаторы
Для достижения того же эффекта используйте конструкторы или списки инициализаторов:
источник
Вы можете просто инициализировать через ctor:
источник
struct address
. Кроме того, типы POD часто намеренно не имеют конструктора и деструктора.Вы даже можете упаковать решение Gui13 в один оператор инициализации:
Отказ от ответственности: я не рекомендую этот стиль
источник
address
а код все равно будет компилироваться с миллионами мест, только инициализируя исходные пять элементов. Лучшая часть инициализации структуры состоит в том, что вы можете иметь всех членов,const
и это заставит вас инициализировать их всехЯ знаю, что этот вопрос довольно старый, но я нашел другой способ инициализации, используя constexpr и curry:
Этот метод также работает для глобальных статических переменных и даже для constexpr. Единственный недостаток - плохая ремонтопригодность: каждый раз, когда другой элемент должен быть инициализирован с помощью этого метода, все методы инициализации элемента должны быть изменены.
источник
Я мог бы что-то упустить здесь, почему бы и нет:
источник
Это не реализовано в C ++. (также
char*
строки? Я надеюсь, что нет).Обычно, если у вас так много параметров, это довольно серьезный запах кода. Но вместо этого, почему бы просто не инициализировать значение структуры и затем назначить каждому члену?
источник
char*
строки? Я надеюсь, что нет)." - Ну, это пример C.char*
ноconst char*
намного более безопасны для типов, и все просто используют,std::string
потому что это намного надежнее.Я нашел этот способ сделать это для глобальных переменных, который не требует изменения исходного определения структуры:
затем объявите переменную нового типа, унаследованную от исходного типа структуры, и используйте конструктор для инициализации полей:
Не так элегантно, как стиль С, хотя ...
Для локальной переменной требуется дополнительный набор mem (this, 0, sizeof (* this)) в начале конструктора, так что это явно не хуже, и ответ @ gui13 более уместен.
(Обратите внимание, что «temp_address» является переменной типа «temp_address», однако этот новый тип наследуется от «адреса» и может использоваться в любом месте, где ожидается «адрес», так что все в порядке.)
источник
Я столкнулся с подобной проблемой сегодня, когда у меня есть структура, которую я хочу заполнить тестовыми данными, которые будут переданы в качестве аргументов функции, которую я тестирую. Я хотел иметь вектор этих структур и искал однострочный метод для инициализации каждой структуры.
Я закончил тем, что в структуре использовал функцию конструктора, которая, как я полагаю, была предложена в нескольких ответах на ваш вопрос.
Вероятно, плохая практика - иметь аргументы конструктора с такими же именами, что и у открытых переменных-членов, что требует использования
this
указателя. Кто-то может предложить редактирование, если есть лучший способ.Который я использовал в своей тестовой функции для вызова тестируемой функции с различными аргументами, подобными этим:
источник
Это возможно, но только если инициализируемая вами структура является структурой POD (обычные старые данные). Он не может содержать никаких методов, конструкторов или даже значений по умолчанию.
источник
В C ++ инициализаторы в стиле C были заменены конструкторами, которые во время компиляции могут обеспечить выполнение только допустимых инициализаций (т.е. после инициализации члены объекта являются согласованными).
Это хорошая практика, но иногда удобна предварительная инициализация, как в вашем примере. ООП решает это с помощью абстрактных классов или шаблонов дизайна .
На мой взгляд, использование этого безопасного способа убивает простоту, и иногда компромисс в безопасности может быть слишком дорогим, поскольку простой код не нуждается в сложном дизайне, чтобы оставаться обслуживаемым.
В качестве альтернативного решения я предлагаю определить макросы с использованием лямбда-выражений, чтобы упростить инициализацию, чтобы она выглядела почти как стиль C:
Макрос ADDRESS расширяется до
который создает и вызывает лямбду. Параметры макроса также разделяются запятыми, поэтому вам нужно заключить инициализатор в скобки и вызвать
Вы также можете написать обобщенный инициализатор макроса
но тогда звонок чуть менее красив
однако вы можете легко определить макрос ADDRESS, используя общий макрос INIT
источник
В GNUC ++ (кажется, устарел с 2.5, давным-давно :) Смотрите ответы здесь: инициализация C struct с использованием меток. Это работает, но как? ), можно инициализировать структуру следующим образом:
источник
Вдохновлен этим действительно аккуратным ответом: ( https://stackoverflow.com/a/49572324/4808079 )
Вы можете сделать закрытие ламбы:
,
Или, если вы хотите быть очень модным
С этим связаны некоторые недостатки, в основном связанные с неинициализированными членами. Судя по комментариям, содержащимся в связанных ответах, он эффективно компилируется, хотя я его не проверял.
В целом, я просто думаю, что это аккуратный подход.
источник