Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Объекты в C++
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
spongebob
Всем привет!

Подскажите, пожалуйста, в каком порядке создаются глобальные объекты программы (экземпляры классов и переменные простых типов)?
В том, в котором они перечислены при объявлении?
Компилятор WinAVR.
Имеет ли значение вид компилятора C++?
sergeeff
Порядок вызова глобальных конструкторов не регламентирован.
spongebob
Цитата(sergeeff @ Dec 22 2010, 00:17) *
Порядок вызова глобальных конструкторов не регламентирован.


Т. е., получается, что мы не знаем, какой объект создастся первым, а какой последним? А если, к примеру, объект 2 зависит от объекта 1 и объект 1 должен быть создан до объекта 2 (применительно к классам)?
kurtis
Именно, даже существуют методики, которые гарантируют что обьект А будет создан раньше обьекта Б. А вообще, если у вас сильная зависимость между классами, то возможно, следует пересмотреть иерархию классов.

Чтоб не быть голословным, вот пример:

Код
class SomeFoo {
    public:
        int func1() { ... };
};

/* функция возвращает ссылку на обьект типа SomeFoo */
SomeFoo& some_func()
{
    /* статически создаем обьект типа SomeFoo */
    static SomeFoo myClass;
    
    /* возвращаем ссылку на статический обьект */
    return myClass;
}

class SomeOtherClass {
    public:
        my_other_func() {
            int some_value = some_func().func1();
        };
};


надеюсь из кода все понятно. Общий смысл в том, что в функции создается статический объект, ссылка на который, потом возвращается туда куда нам надо. Мне такой трюк нужен был только однажды, да и то, потом как-то обошлось, поменял немного архитектуру.
Сергей Борщ
QUOTE (spongebob @ Dec 21 2010, 23:06) *
в каком порядке создаются глобальные объекты программы
В том порядке, в котором линкер сложит секции *(.ctors*). В пределах одной единицы компиляции получаются в порядке объявления. Между единицами компиляции - можно сортировать по имени файла, можно еще по каким-то признакам (точно не помню). Все это описывается строкой скрипта KEEP(SORT(*)(.ctors)). Описание - (в том числе и сортировок) - в документации на линкер директива SORT(). Но все это нестандандартно и от лукавого, закладываться на это - делать код неперносимым на другой компилятор. Нужна ли такая переносимость если gcc есть под все процы с которыми работаете - решать вам.
sergeeff
Это к сожалению тонкости конкретного компилятора и я бы на них не полагался.
spongebob
Фактически, ситуация следующая (возможно, посоветуете что-нибудь лучше).
Допустим, в проекте есть несколько глобальных переменных, которые используются в нескольких модулях.
Мы преследуем две цели: задать порядок создания и облегчить включение глобальных переменных в несколько модулей.
Создаем "x.cpp", в котором определяем все наши глобальные объекты, в файле "x.hpp" объявляем все эти объекты, используя директиву "extern". Далее инклудим файл "x.hpp" в нужные нам .cpp.

Цитата
Но все это нестандандартно и от лукавого


Понимаю теперь, будем от этого уходить sm.gif
dxp
Цитата(spongebob @ Dec 22 2010, 04:44) *
Фактически, ситуация следующая (возможно, посоветуете что-нибудь лучше).
Допустим, в проекте есть несколько глобальных переменных, которые используются в нескольких модулях.
Мы преследуем две цели: задать порядок создания и облегчить включение глобальных переменных в несколько модулей.
Создаем "x.cpp", в котором определяем все наши глобальные объекты, в файле "x.hpp" объявляем все эти объекты, используя директиву "extern". Далее инклудим файл "x.hpp" в нужные нам .cpp.

Да, для одной единицы трансляции гарантируется порядок создания объектов. Если зависимые объекты размещать в одной единице трансляции, то проблем нет. В противном случае надо применять разного рода трюки - например, уже не раз тут (на форуме) упоминавшийся singleton.
sergeeff
Цитата(dxp @ Dec 22 2010, 08:54) *
Да, для одной единицы трансляции гарантируется порядок создания объектов. Если зависимые объекты размещать в одной единице трансляции, то проблем нет. В противном случае надо применять разного рода трюки - например, уже не раз тут (на форуме) упоминавшийся singleton.


singleton гарантирует, что объект будет создан только один раз и мы сами должны вызвать его Instance в нужном месте и в нужное время. Таким образом это не есть глобальный объект в обычном понимании, конструктор которого компилятор сам помещает в специальную таблицу, обеспечивая вызов конструкторов до main().
ReAl
Цитата(kurtis @ Dec 22 2010, 00:15) *
Общий смысл в том, что в функции создается статический объект, ссылка на который, потом возвращается туда куда нам надо.
Всё так, только инициализируется этот объект именно в момент вызова функции (собственно, для гарантии наличия, функция-то может вызываться и из других конструкторов), что тянет за собой дополнительную флаговую переменную со смыслом bool initialised; и соответствующий код. А при отсутствии (это я уже о gcc) -fno-threadsafe-statics там ещё и мьютексы __cxa_guard_*
В мелких мелкоконтроллерах жаба давить начинает.
Цитата(kurtis @ Dec 22 2010, 00:15) *
Мне такой трюк нужен был только однажды, да и то, потом как-то обошлось, поменял немного архитектуру.
dxp
Цитата(sergeeff @ Dec 22 2010, 13:00) *
singleton гарантирует, что объект будет создан только один раз и мы сами должны вызвать его Instance в нужном месте и в нужное время. Таким образом это не есть глобальный объект в обычном понимании, конструктор которого компилятор сам помещает в специальную таблицу, обеспечивая вызов конструкторов до main().

Конечно. Это просто один из путей обхода проблем, возникающих от неопределенности порядка создания объектов, объявленных в разных единицах трансляции.
spongebob
Всем спасибо sm.gif
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.