Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Порядок инициализации глобальных объектов  (Прочитано 3095 раз)
0 Пользователей и 1 Гость смотрят эту тему.
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« : 12-09-2013 20:09 » 

Как-то я об этом не задумывался. Жили-были себе спокойно несколько синглетонов. Объявлены они были статически как глобальные переменные внутри cpp файлов. Причём одни (обёртки) обращаются к другим прямо во время создания.
Код: (C++)
MyClass singletonInstance;
Сделано было так специально, чтобы не заводить динамически создаваемые объекты - для них при завершении работы программы не вызываются деструкторы, да и память не чистится.

И вот в один прекрасный день - сегодня - вдруг всё сломалось. При инициализации вдруг обёртки стали находить другие объекты ещё не созданными.

По стандарту вроде бы порядок инициализации неопределённый. Т.е. до сих пор мне просто везло.

Ну первое, что приходит в голову - ленивая инициализация по первому запросу + умный указатель.

Какие ещё могут быть решения?

P.S. Важно, что всё это в один модуль не собрать.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #1 : 12-09-2013 20:23 » 

А вызов инициализаторов нельзя в кучку собрать? Даже можно сделать это динамически, через мейкфайл, при некоторых правилах именования файлов и переменных. Сформировать на основе списка файлов cpp-модуль, содержащий некоторую заранее известную функцию, динамически наполненную вызовами инициализаторов. Правда, если хочется определенный порядок инициализации, то лучше и надежнее будет сделать это руками. Например, у нас в проекте несколько серверов разного назначения, использующие общие модули: в индивидуальных файлах этих серверов прописано, какие модули и в каком порядке загружаются.
« Последнее редактирование: 12-09-2013 20:27 от RXL » Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
sss
Специалист

ru
Offline Offline

« Ответ #2 : 13-09-2013 09:22 » 

Я вот так использую точно инициализированный глобальный объект. Это исключение из правил...
Зато работаем на этапе создания статических объектов.
Код:

CMemoryManager*        g_MM = NULL;
CMemoryManager& __GlobalMM()
{
  if ( g_MM == NULL) g_MM = new CMemoryManager();
  return *g_MM;
}

PVOID CMemoryManager::__MemAlloc( size_t stBytesCount) throw ( ELowResources*)


#define MemAlloc        __GlobalMM().__MemAlloc



И потом пишу

Код:

 p = MemAlloc(10);



« Последнее редактирование: 13-09-2013 09:24 от sss » Записан

while (8==8)
Вад
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #3 : 13-09-2013 10:12 » 

Если потокобезопасность не нужна, я использую статическую переменную внутри функции, возвращающей ссылку/указатель на нужный синглетон.
Записан
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #4 : 13-09-2013 14:25 » 

Вад, так и я тоже. Дело ж не в этом, а в порядке срабатывания конструкторов этих синглетонов.

sss, слабо понял, зачем этот наворот. И ко всему прочему непонятна судьба объекта в куче при завершении работы программы. Если судьба его "потерялся - и фиг с ним", мне это категорически не подходит, мне в деструкторе системные ресурсы освобождать надо.


Сделал на умном указателе ленивую инициализацию - по первому обращению. Ну типа:
Код: (C++)
class MyClass
{
private:
  /* ... */
  static std::auto_ptr<MyClass> instance;
  MyClass() { /* ... */ }
  MyClass(const MyClass &copy) { /* ... */ }
public:
  MyClass *Instance()
  {
    MyClass *obj = MyClass::instance.get();
    if(obj == NULL)
    {
      obj = new MyClass();
      MyClass::instance.reset(obj);
    }
    return obj;
  }
  /* ... */
};
std::auto_ptr<MyClass> MyClass::instance;
« Последнее редактирование: 13-09-2013 14:30 от Dimka » Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
sss
Специалист

ru
Offline Offline

« Ответ #5 : 13-09-2013 14:45 » 


sss, слабо понял, зачем этот наворот. И ко всему прочему непонятна судьба объекта в куче при завершении работы программы. Если судьба его "потерялся - и фиг с ним", мне это категорически не подходит, мне в деструкторе системные ресурсы освобождать надо.


Блин удалить можно внутри освобождения последней ссылки на объект MemFree(p). Наворот нужен для того, что бы быть уверенным что объект создан при первом обращении к нему 
при этом реализация скрыта.
Записан

while (8==8)
Вад
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #6 : 13-09-2013 17:28 » 

Вад, так и я тоже. Дело ж не в этом, а в порядке срабатывания конструкторов этих синглетонов.
Ты написал, что у тебя глобальные статические переменные.
У меня локальные Улыбаюсь Я делаю что-то вроде
Код: (C++)
MyClass * Instance()
{
    static MyClass instance(/*params*/);
    return &instance;
}
Инициализация локальных статических переменных - при первом входе в функцию. Это и есть твоя ленивая инициализация, и должна происходить с сохранением строгого порядка, если одна функция-аксессор вдруг вызовет ещё одну подобную.
« Последнее редактирование: 13-09-2013 17:33 от Вад » Записан
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #7 : 13-09-2013 20:18 » 

Вад, это мысль интересная и плодотворная.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines