Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Последовательность вызова конструкторов
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > Cредства разработки для МК > IAR
Andy Mozzhevilov
Вопрос, можно ли как-то средствами расширения языка, а также параметрами и скриптами линкера (IAR ARM 5.xx) задать посделовательность инициализации (вызовов конструкторов) глобальных объектов?
То есть, например:
Код
class TSlon
{
....
};

class TMamont
{
....
};

TSlon    Slon;   // Этот объект должен быть инициализирован первым при запуске
TMamont  Mamont; // Этот объект должен быть инициализирован вторым при запуске

dxp
Цитата(Andy Mozzhevilov @ Sep 23 2010, 14:33) *
Вопрос, можно ли как-то средствами расширения языка, а также параметрами и скриптами линкера (IAR ARM 5.xx) задать посделовательность инициализации (вызовов конструкторов) глобальных объектов?

Если объекты объявляются в одной единице трансляции, то гарантируется тот порядок их создания, в котором они объявлены.

TSlon slon;
TMamont mamont;

slon будет создан первым, mamont за ним.

Если объекты объявлены в разных единицах трансляции, то тут порядок создания не гарантируется. Избавиться от зависимости создания в этом случае можно дополнительными ухищрениями - например, с помощью singleton'а.
Dima_G
В свое время отказался от раздумий по очередности вызова конструкторов глобальных объектов.
Сейчас использую следующую схему:
1) Собственно сам конструктор
2) Этап Init()
3) Этам Run()

В самом конструкторе объект ведет себя изолированно от внешнего мира. Категорически не допускается взаимодействия с другими объектами (они у меня зачастую в другой единицы трансляции)
На этапе Init() происходит "налаживание связей" между объектами (обмен информацией, финальная инициализация и тд). На этапе Run() запускаются таски, включаются прерывания и тд.
Этапы Init и Run запускаются из main, что гарантирует создание глобальных объектов к этому моменту.

Код
///@function main()
///Main function
int main()
{
  * * *
  ClSystemService::Instance()->InitServices();
  ClSystemService::Instance()->RunServices();
  * * *
}


Либо возможен другой вариант: использование паттерна Singleton. Тогда обращение к объекту будет гарантировать его наличие smile.gif
Andy Mozzhevilov
Цитата(Dima_G @ Sep 23 2010, 13:23) *
На этапе Init() происходит "налаживание связей" между объектами (обмен информацией, финальная инициализация и тд).

Вызывать отдельно Инит для каждого объекта - это надо не забыть об этом.
Иногда (и зачастую) объект создается просто глобально, а потом живет своей жизнью. Дополнительные init и run - потенциальная возможность забыть их сделать, соответственно допустить ошибку, которую потом возможно будет трудно поймать.
Объект, который мне нужно заинитить первым - он один в системе.
Точнее нужно вызвать инициализацию ОС, чтобы в конструкторах всех глобальных объектов можно было использовать функции ОС по созданию сервисов (семафоров, очередей и т.п.). Иначе нужно разносить в каждом классе создание объекта и его инициализацию - это достаточно трудоемко.
Dima_G
Цитата(Andy Mozzhevilov @ Sep 23 2010, 21:17) *
Вызывать отдельно Инит для каждого объекта - это надо не забыть об этом.


На самом деле я маленько слукавил smile.gif Если на пальцах, то у меня юсается следующая архитектура:
1) Реализована система широковещательных посылок. Те посылка (объект) не имеет адресата, она лишь имеет характеристику "тип посылки". (те посылки могут иметь тип "int", тип "ClSlon" и тд - типом посылки может быть любой тип, который может быть параметром шаблона (особенности реализации)). Объекты могут подписываться на определенный тип сообщений. Адресант сообщений ничего не знает об адресатах.
2) Есть сообщения типа "Init", "Run"
3) Все сервисы наследуются от базового класса, который подписан на сообщения Init, Run и при их получении вызывает свои виртульные методы.

Соответственно, в main-е я просто посылаю широковещательные сообщения, а сервисы их ловят и происходят необходимые действия. Таким образом я исключаю возможность "забыть проинициализировать" объект. Да и вообще - я в main-е ничего о них не знаю

Цитата(Andy Mozzhevilov @ Sep 23 2010, 21:17) *
Объект, который мне нужно заинитить первым - он один в системе.
Точнее нужно вызвать инициализацию ОС, чтобы в конструкторах всех глобальных объектов можно было использовать функции ОС по созданию сервисов (семафоров, очередей и т.п.).


Тогда прямая дорога - использование синглетонов. Самый простейший (не самый лучший) способ:

Код
template <class T>
class TClSingleton
{
  public:
    inline static T& Instance()
    {
      static T clObj_;
      retrun T;
    }
};

class ClSingleObject: public TClSingleton<ClSingleObject>
{
  frined class TClSingleton<ClSingleObject>;
  
  private:
    ClSingleObject(){...}
    ClSingleObject(const ClSingleObject&){..}

  public:
    void fun();
};

* * *
ClSingleObject::Instance()->fun();
* * *


В крайней строчке мы вызываем метод объекта, причем не имея самого объекта. Он будет создан при первом вызове и не будет продублирован при последующих.
AHTOXA
Цитата(Dima_G @ Sep 23 2010, 21:21) *
Самый простейший (не самый лучший) способ:


Что-то как-то сложно. Я делаю проще:

singleton.h:
Код
#ifndef SINGLETON_H_
#define SINGLETON_H_

template<typename T> class singleton
{
public:
    static T& Instance() __attribute__((__noinline__))
    {
        static T instance;
        return instance;
    }
};
#endif /* SINGLETON_H_ */

А определение
Код
uart_t uart;

заменяю на
Код
uart_t& uart = singleton<uart_t>::Instance();


И телемаркет smile.gif
Dima_G
Цитата(AHTOXA @ Sep 23 2010, 23:12) *
Что-то как-то сложно. Я делаю проще:

Да то же самое smile.gif
А, если не секрет, почему noinline?
AHTOXA
Цитата(Dima_G @ Sep 23 2010, 22:48) *
А, если не секрет, почему noinline?


Компилятор ругался, что не удалось заинлайнить.
gladov
Цитата(AHTOXA @ Sep 23 2010, 20:12) *
Что-то как-то сложно. Я делаю проще:

...

И телемаркет smile.gif


А дело в том, что паттерн singleton по своей сути должен гарантировать что в системе будет существовать только один объект данного класса. Если же не объявить упомянутый в примере uart_t как наследник singleton'a и не сделать у него приватных конструкторов, как это сделано у Dima_G, то компилятор разрешит сделать так:
Код
uart_t *U1 = new uart_t;
uart_t *U2 = new uart_t;
uart_t& U3 = singleton<uart_t>::Instance();

Получим 3 объекта класса uart_t. Значит автор кода должен помнить, что создавать объеты данного класса напрямую низя.
В варианте от Dima_G на уровне копилятора гарантируется, что объект класса ClSingleObject будет единственный и наплодить других не получится.
shreck
В догонку.
Цитата(AHTOXA @ Sep 23 2010, 23:12) *
А определение
Код
...

заменяю на
Код
uart_t& uart = singleton<uart_t>::Instance();

И телемаркет smile.gif


Использование ссылки uart, проинициализированной динамически - может быть засада. Насколько я помню, такая инициализация выполняется чуть ли не самой последней. И, например, конструктор некоторого объекта, использующего в своем теле uart, обломается.
Синглетоны на то и синглетоны. Обращаться к ним всегда надо именно через instance().
AHTOXA
Цитата(gladov @ Oct 13 2010, 00:49) *
В варианте от Dima_G на уровне копилятора гарантируется, что объект класса ClSingleObject будет единственный и наплодить других не получится.


Понятно, спасибо за разъяснения.

Цитата(shreck @ Oct 13 2010, 08:14) *
Использование ссылки uart, проинициализированной динамически - может быть засада. Насколько я помню, такая инициализация выполняется чуть ли не самой последней. И, например, конструктор некоторого объекта, использующего в своем теле uart, обломается.


Да, вы правы. Я забыл упомянуть, что в конструкторах я использую локальную ссылку, и инициализирую её отдельно. А та, глобальная ссылка - это уже на потом, чтоб не менять остальной код, который раньше работал с обычной переменной uart smile.gif
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.