Предположим, в терминах C++, что есть ряд глобальных объектов. Которые к тому же взаимодействуют между собой без определённого порядка (нет чёткой иерархии, нельзя часть из них сделать вложенными в другие). Чтобы вся система работала нужно чтоб не было ситуации использования объекта до вызова его конструктора. Если бы можно было исключить вызов в конструкторе методов других объектов (классов), то нет проблем. Но де-факто это сделать сложно и всё равно потребуется механизм о котором речь пойдёт ниже. Нужен, стало быть, определённый порядок вызова конструкторов. Например, GCC предлагает такой вариант такой вариант.
Неудобство в том, что нужно вручную назначать эти цифры приоритета и где-то на бумажке записать шпаргалку, чтоб не ошибиться. Аналогичная проблема существует в init-скриптах unix-подобных систем. Там тоже запуск части сервисов (демонов, служб) привязан к другим которые должны быть запущены раньше. в SysV init это решается так же -- цифрами. Есть и более простой механизм а-ля BSD 3-й версии -- просто вручную вызвать что нужно из вручную написанного /etc/rc.init (вручную вызвать нужные функции из main()...) Этот простой механизм применительно к программированию на C/C++ неудобен необходимостью ручной поддержки этого списка, и в частности, нельзя из одного набора исходников получать разные бинарники просто путём включения/исключения ненужных *.o файлов -- что совсем уж неудобно.
Речь вообще не о C++, а о plain C, но сущности это не меняет, просто так трудней с терминологией. Такой механизм, подобный init_priority в GCC или SysV init и сделан. Но он этими цифрами и неудобен. Хотелось бы автоматического разрешения зависимостей, кто от кого зависит, и соответственно определённого порядка запуска. Как бы эту задачу разрешить в рамках C-компилятора? Сейчас в в рамках C++ разрешается через конструкторы, вызываемые до main, в рамках C похожим образом через ручной их вызов из main по списку с приоритетами, формируемому в момент компиляции -- адреса "конструкторов" кладутся в специальную секцию линкером (по которой потом пробегается функция вызванная из main() и вызывает в порядке приоритета). Но хотелось бы избавиться от ручного назначения цифр.
Понятно, что компилятор сам не вызовет в нужном порядке. Максимум можно получить какой-то массив, в котором есть указатели на фунции и как-то описаны их зависимости и далее отдельная функция должна решить какой должен быть порядок и в этом порядке вызвать (уже в рантайме). Вначале вызываем конструкторы ни от чего не зависимых объектов, потом зависимости от этих объектов считаем разрешёнными и так в рекурсии. И запоминаем какие уже (делаем singleton) вызваны. Кажется медленным, наверное можно пойти с другого конца -- брать первый попавшийся класс и спускаться по дереву его зависимостей до конца.
Как описывать зависимости? Описателем зависимостей может являться ссылка на список указателей конструкторов классов от которых зависит каждый конкретный класс. Т.е. в специальную секцию помещаются не список указателей на конструкторы с их приоритетом (как сейчас):
Можно даже static объекты делать, не видимые за пределами модуля, с именем anonymous#__LINE__, но от них ничего зависеть не должно, они должны быть только зависимые.
Может как-то по другому можно?
Re: Детерминированный порядок вызова конструкторов, с зависимостями.
Здравствуйте, fk0, Вы писали:
fk0> Предположим, в терминах C++, что есть ряд глобальных объектов. Которые к тому же взаимодействуют между собой без определённого порядка (нет чёткой иерархии, нельзя часть из них сделать вложенными в другие). Чтобы вся система работала нужно чтоб не было ситуации использования объекта до вызова его конструктора. Если бы можно было исключить вызов в конструкторе методов других объектов (классов), то нет проблем.
Если проблема только в конструкторах, то синглетон мейерса спасет положение.
Порядка вызова деструкторов он, ессно, не гарантирует.
_____________________
С уважением,
Stanislav V. Zudin
Re: Детерминированный порядок вызова конструкторов, с зависимостями.
Здравствуйте, fk0, Вы писали:
fk0> Чтобы вся система работала нужно чтоб не было ситуации использования объекта до вызова его конструктора. google://two phase initialization c++
Если вкратце — то сначала мы конструируем всё, затем проставляем взаимные ссылки и стартуем. На крайняк — lazy-обёртки, создающие объект при первом реальном обращении к нему.
fk0> Как описывать зависимости? google://dependency injection c++
Если вкратце — описываем набор зависимостей между сущностями, порядок инстанциирования будет выведен автоматически
Re[2]: Детерминированный порядок вызова конструкторов, с зависимостями.
Здравствуйте, Mr.Delphist, Вы писали:
fk0>> Как описывать зависимости? MD>google://dependency injection c++ MD>Если вкратце — описываем набор зависимостей между сущностями, порядок инстанциирования будет выведен автоматически
2/21/2014 3:50 PM, fk0 пишет:
> Предположим, в терминах C++, что есть ряд глобальных объектов. Которые к > тому же взаимодействуют между собой без определённого порядка (нет > чёткой иерархии, нельзя часть из них сделать вложенными в другие). Чтобы > вся система работала нужно чтоб не было ситуации использования объекта > до вызова его конструктора.
Зависит от твоих целей.
Если сделать код как можно круче и показать всем, какой ты крутой, то
двигайся в стороны "паттернов", как тебе уже накидали гору советов.
Если же, чтобы работало, то запихать всю эту помойку в один класс, там
сделать инициализацию в нужном тебе порядке. А затем рефакторить код,
чтобы избавиться от этого дерьма.
Posted via RSDN NNTP Server 2.1 beta
Re: Детерминированный порядок вызова конструкторов, с зависимостями.
Т.е. мы создаём в cpp файле объект и декларируем некоторую функцию, которая может быть использована для определения зависимостей.
В данном случая, сам объект зависит от GetPlanInitNode_Exception и GetPlanInitNode_Task.
Дальше при старте программы все таким образам определённые объекты создаются до вызова конструкторов обычных глобальных объектов с учётом зависимостей.
Если возникает циклическая зависимость, происходит аборт.
В реализации используются расширения gcc -- инициализация с приоритетом. Для нужд PlanInit зарезервированы три приоритета.