Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
Форум программистов > C/C++: Общие вопросы > Инициализация константного динамического массива |
Автор: JackYF 6.4.2007, 23:56 |
Возможно, данная тема уже пробегала на форуме. Однако, в поиске не нашел. Итак, проблема следующая. Есть некий класс, у которого есть константное поле. Раз поле константное, то оно должно ициализироваться в конструкторе. Но мне нужно создать (динамически) массив элементов данного класса, причем каждому элементу нужно задать свои параметры конструктора. Какие есть варианты, кроме malloc + placement new (и связанных потом с этим извращений)? |
Автор: vinter 7.4.2007, 00:01 |
остается еще явная инициализация, по другому вроде никак. |
Автор: threef 7.4.2007, 00:20 | ||
Синтаксически создать массив констант нельзя. Предлагались статические варианты или,ИМХО лучший - создать структуру, содержащую массив. Ее-то и можно проинициализировать в конструкторе.
|
Автор: Xenon 7.4.2007, 01:28 |
... Недопонял ![]() |
Автор: JackYF 7.4.2007, 11:49 |
threef, через список инициализаторов не пойдет. Мне нужен полноценный вызов конструктора с несколькими параметрами для каждого элемента.... |
Автор: Xenon 7.4.2007, 12:42 | ||
Может так?
|
Автор: JackYF 7.4.2007, 13:58 | ||
Xenon, честно - не понял, что ты этим хотел сказать... Мне при создании каждого элемента нужно ему в конструктор передать разные параметры... то есть мне надо сделать код, который будет работать как:
|
Автор: Daevaorn 7.4.2007, 14:48 |
Он тебе показал решение |
Автор: Xenon 7.4.2007, 16:22 |
JackYF, Я просто не очень понял что ты хотел. Исходя из заголовка я понял, что тебе нужен в классе константный динамический массив, который ты сможешь иницилизировать значениями, переданными в конструктор. Вот я тебе исходя из этих данных накидал пример. Какая у тебя задача-то стоит? Зачем ЭТО? |
Автор: likehood 7.4.2007, 16:35 |
JackYF, может http://www.lib.ru/CTOTOR/cpp3comm.txt#297 подойдет. |
Автор: likehood 7.4.2007, 17:04 | ||
можно еще вместо массива использовать вектор:
|
Автор: JackYF 7.4.2007, 23:35 |
по-моему, тоже не пойдет. Вектор для присваивания будет использовать стандартную семантику присваивания, то есть operator=. Что в данное случае опять-таки недопустимо, присваивание константным элементам класса можно только в конструкторе. Вообще говоря, такая задача возникает уже второй раз... Зачем было первый, не помню. А вот вкратце кусок задачи - постараюсь объяснить... Есть класс. В котором содержится массив объектов. Массив public. Каждый объект содержит содержит несколько полей, из которых пользователь может все читать, но только часть писать. Те 2 поля, которые константные, инициализируются один раз при создании и больше не изменяются. Я подумал, что с точки зрения семантики лучше всего сделать было их константными, и тогда вопрос решался сам собой - данные инициализировались в надклассе массива, а потом можно было выдать пользователю данный массив. Пока писал, назрело, правда, еще одно решение... Сделать эти поля не константыми, а приватными у класса, фукнцию их чтения public, функцию их записи в приват и френдом надкласс. Да, это выход. Но это менее красиво... Да ну и вообще интересно с той точки зрения, что вообще с точки зрения программиста желания сделать массив с описанными мной свойствами возможно; и для компилятора, в общем-то, не проблема... Но вот не получается. |
Автор: JackYF 7.4.2007, 23:53 |
Нет, не пойдет... опять все сводится к создание уже созданного массива значений и присваивания. Ни массива у меня нету и быть не может (а зачем мне тогда делать еще один? я лучше указатель создам), ни присваивания... (выше написал, почему). |
Автор: Earnest 9.4.2007, 20:36 | ||||
Срочно меняй свои представления о красоте! ![]()
Один (уж не помню кто) из столпов программирования писал, что любую проблемму в программировании можно решить добавлением нужного числа прокладок в нужные места. Цитирую не дословно, но смысл тот. Вот и здесь то же самое, treef уже предлагал: дополнительная структура, содержащая твой массив. массив в структуре не константный, поэтому инициализируй его как хочешь. А саму структуру в объемлющем классе сделай константной. Точно, была уже такая тема, и там это предлагали, может даже я... Но лучше так не делай, а все спрячь подальше. Public-данные - это ЗЛО! |
Автор: JackYF 10.4.2007, 00:39 |
likehood, мне надо будет отдавать пользователю ссылки на элементы массива. В данном случае тип элементов foo_local, о котором пользовает не знает и не узнает, так как он локальный. Ну, не всегда. Особенно если они константные... чем? уже созданным внешне массивом? Как хочу? Дык вот я и хочу! Вызвать разные конструкторы для разных элементов массива. Но как? Проблема - инициализация массива! Ы, тоже не мой выход. Некоторые данные должны остаться public. Earnest, вариант threef'a не подходит. Он предлагает инициализировать надструктуру. Опять-таки - чем? У меня не POD-данные, чтобы их в инициализаторе прописывать между фигурными скобками... Задача - вызов конструкторов. И без локальных классов, мне потом надо будет эти ссылки на эти данные выводить наружу. Подводя по крайней мере промежуточный итог, резюмирую... не буду предоставлять public-const данные, сделаю через функции. Но вот абстрактный вопрос инициализации массива до сих пор не решен. Скорее всего, все-таки нельзя. А жалко. |
Автор: Earnest 10.4.2007, 07:49 |
Если массив не константный, то никто не мешает писать в конструкторе структуры: a[0] = XXX; a[1] = YYY; и т.д. Нужно только позаботиться, чтобы элементы массива имели default-конструкторы. Что ты передашь в надструктуру для инициализации - твоя проблема, хоть из файла данные читай. Ты писал изначально о невозможности вызвать конструкторы для каждого элемента массива. Так вот, эта проблема решается в рамках описанного подхода. А как ты разом передашь для разных элементов инициализирующие данные - совсем другая проблема. |
Автор: JackYF 10.4.2007, 14:14 |
Operator= не подходит... Уже говорил же ж. Если делать константными данными. Решение с помощью закрытия данных и работы через функции принято. Вопрос, как вызвать конструкторы элементов массива. Без использования операторов=. Просто абстрагируясь от моей проблемы: как вызвать <u>конструкторы</u> элементов массива. Не присваивания потом или через внешние структуры. Сам факт. Нет - значит нет, дело же такое ![]() |
Автор: likehood 10.4.2007, 14:33 | ||
Вообще-то, в моем примере тип массива Foo*, так что никаких проблем. Приведение к базовому классу еще никто не отменял. |
Автор: JackYF 10.4.2007, 14:38 | ||
Соглашусь. Но проблема прямого вызова конструкторов не решена. Мне надо это запихнуть в массив без operator=. Если выдавать элементы по одному, то такое не выйдет. |
Автор: SerpentVV 10.4.2007, 14:53 | ||||||||||||||
Поля-массивы в классе До сих пор в качестве полей мы использовали только скалярные переменные. Но в С++ нет запрета объявлять в классе поле-массив. Естественно, размер класса с полем-массивом увеличивается на размер массива. Однако использование массива в классе имеет некоторые нюансы, связанные с инициализацией . Начнем разбираться с этим вопросом на самом простом примере (листинг 2.23), в котором объявляются и инициализируются несколько полей-массивов.
В классе Arrays объявлено три поля-массива: m0, m1 и m2. Как видим, задать количество элементов массива можно либо явной константой, либо константным выражением со статическими и/или нумерованными константами, причем константы должны быть определены раньше массива. Задавать количество элементов поля-массива обязательно. Конструктор без аргументов обнуляет массивы, выполняя цикл в теле. Такой способ инициализации поля-массива — в теле конструктора — является наиболее простым. Это позволяет присвоить элементам массива любые значения. Однако наиболее часто выполняется обнуление, поэтому для массивов разрешается применять инициализацию нулем. Тогда наш конструктор выглядит значительно проще:
Для массива объектов некоторого типа такая запись означает вызов конструктора по умолчанию (без аргументов), и не забудьте, что этот вызов выполняется для каждого элемента массива. К сожалению, применение списков инициализации для полей-массивов этим и ограничивается — в скобках нельзя ничего указывать. Явная инициализация не проходит даже для символьных массивов. Например, если мы объявим в классе Arrays символьный массив
и попытаемся в списке инициализации конструктора присвоить этому массиву символьную константу,
то в системе Visual C++.NET 2003 получим сообщение об ошибке: error C2536: 'Arrays::Arrays::s' : cannot specify explicit initializer for arrays нельзя определять явный инициализатор для массивов Однако мы можем прописать в классе поле-указатель на символ
и инициализировать его символьной константой в списке инициализации конструктора, как показано выше. Как это ни странно, но большие проблемы возникают при попытках объявить в классе константный массив встроенного типа! Как мы выяснили выше, константы не могут быть проинициализированы в теле конструктора и инициализируются только в списке инициализации конструктора. Однако для константного массива встроенного типа не работает даже инициализация нулем. ПРИМЕЧАНИЕ Этот вопрос практически не отражен в стандарте, поэтому компиляторы ведут себя по-разному. В системе Visual C++.NET 2003 выдается ошибка компиляции C2439, а Borland C++ Builder 6 выдает только предупреждение W8038 о том, что массив не инициализируется. Не проходит и отмена константности. Например, мы пропишем массив m0 как константный, а в теле конструктора пропишем инициализацию в цикле
И система Visual C++.NET 2003, и Borland C++ Builder 6 откажутся компилировать такой цикл. Удивительно, но для константного массива объектов не встроенного типа задавать инициализацию нулем разрешается. Для этого в классе должен быть определен конструктор без аргументов, который вызывается для инициализации каждого элемента константного поля-массива. Например, вполне можно инициализировать константный массив строк,
прописав в списке инициализации конструктора инициализацию «нулем» ss(). Как реально инициализируется такой массив, конечно, зависит от реализации конструктора по умолчанию. |
Автор: JackYF 10.4.2007, 15:01 |
SerpentVV, это все было к чему? |
Автор: likehood 10.4.2007, 15:04 |
Может я плохо понял задачу, но в моем примере operator= не используется, присваивание идет через список инициализации. |
Автор: JackYF 10.4.2007, 16:12 |
Задача - вызов конструкторов для каждого элемента массива. Список инициализации работает только для POD-типов, тем более значения, передаваемые в конструктор, мне не известны в начале программы. |
Автор: likehood 10.4.2007, 16:15 |
Ну так в моем примере передаваемые значения и вычисляются во время работы программы. Кстати, почему это список инициализации работает только для POD-типов? Добавлено через 2 минуты и 53 секунды Может мы говорим о разных вещах? ![]() Я говорю об http://forum.vingrad.ru/index.php?showtopic=145000&view=findpost&p=1091495 посте. |
Автор: JackYF 10.4.2007, 17:41 | ||||
Хм... приведи контрпример.
да... недосмотрел я тогда, видать. Возможно, это выход. Попробую применить. Спасибо. Ввиду этого дела... там где раньше в постах переборщил, извините... хорошо же меня понесло. |
Автор: likehood 10.4.2007, 18:23 |
Все же локальные классы - довольно экзотическая вещь. Пожалуй, лучшем вариантом будет предложенный Earnest. Видимо, я тебя неправильно понял. Ты, наверное, под списком инициализации имел ввиду пример threef'а, а я подумал о другом. В таком случае согласен насчет POD-типов. Разве ж это переборщил. Тут такие перлы иногда выдают... ![]() |
Автор: SerpentVV 11.4.2007, 12:10 | ||
Это к тому, что в списке инициализации вызывается конструктор по умолчанию - для неPOD-типов. Во-вторых, к тому, что о полях-константных массивах в стандарте нет практически ничего. В третьих, несколько противоречивая постановка: инициализировать константный массив значениями, которые не известны в начале работы программы... Тогда это - не константный массив, если значения констант неизвестны при компиляции... Если есть желание просто защитить от изменений - нет нужны объявлять массив константным... Можно решить этот вопрос на уровне прав доступа... |
Автор: JackYF 11.4.2007, 15:01 | ||||
Никаких противоречий...
Такой код тебя не смущает? А ведь значение явно не будет известно на этапе компиляции... Так и у меня. У меня некоторые поля класса константные... Которые, естественно, инициализируются в конструкторе. Не по-умолчанию... А в принципе, как минимум два пути решения вопроса уже озвучены. 1) с помощью прав доступа 2) с помощью локальных классов Всем спасибо, тему можно закрывать. |
Автор: SerpentVV 11.4.2007, 15:27 |
Ага, понял... Логическая константность, естественно, не всегда равна физической... ![]() |