C++: Когда (и как) является C++ Глобальными Статическими Вызванными Конструкторами?

Я нашел Ваш вопрос действительно интересным.
Обычно мне нужны объекты объектов инкапсулировать бизнес-логику приложения. Это было бы действительно сложным и несоответствующим для продвижения этой логики на слой данных.
, Что Вы сделали бы для предотвращения этих объектов объектов? Какое решение Вы имеете в виду?

24
задан Matthew Iselin 13 August 2009 в 11:08
поделиться

5 ответов

Когда речь идет о нелокальных статических объектах, гарантий не так много. Как вы уже знаете (и это также упоминалось здесь), он не должен писать код, который зависит от этого. Фиаско с порядком статической инициализации ...

Статические объекты проходят двухфазную инициализацию: статическую инициализацию и динамическую инициализацию. Первое происходит первым и выполняет инициализацию нулем или инициализацию константными выражениями. Последнее происходит после завершения статической инициализации. Это происходит, например, когда вызываются конструкторы.

Как правило, эта инициализация происходит за некоторое время до main (). Однако, в отличие от того, что многие думают, даже это не гарантируется стандартом C ++. Фактически гарантируется, что инициализация выполняется перед использованием любой функции или объекта, определенных в той же единице трансляции, что и инициализируемый объект. Обратите внимание, что это не зависит от ОС. Это правила C ++. Вот цитата из стандарта:

Это определяется реализацией, будет ли динамическая инициализация (8.5, 9.4, 12.1, 12.6.1) объекта область пространства имен выполняется перед первым оператором main. Если инициализация отложена до какой-то точки во времени после первого оператора main, это должно произойти до первого использования любой функции или определенного объекта в той же единице трансляции, что и инициализируемый объект
18
ответ дан 28 November 2019 в 23:13
поделиться

Это сильно зависит от компилятора и времени выполнения. Не рекомендуется делать какие-либо предположения о времени создания глобальных объектов.

Это особенно проблема, если у вас есть статический объект, который зависит от другого, уже построенного.

Это называется " фиаско с порядком статической инициализации ". Даже если в вашем коде это не так, стоит прочитать статьи часто задаваемых вопросов по C ++ Lite по этой теме.

10
ответ дан 28 November 2019 в 23:13
поделиться

У вас есть получатели грантов:

  • Все статические нелокальные объекты в глобальном пространстве имен создаются до main ()
  • Все статические нелокальные объекты в другом пространстве имен создаются до любых используются функции / методы в этом пространстве имен (что позволяет компилятору потенциально лениво оценивать их [но не рассчитывать на такое поведение]).
  • Все статические нелокальные объекты в блоке преобразования создаются в порядке объявления .
  • Ничего не определено относительно порядка между единицами трансляции.
  • Все статические нелокальные объекты уничтожаются в порядке, обратном их созданию. (Это включает в себя статические функциональные переменные (которые лениво создаются при первом использовании).

Если у вас есть глобальные объекты, которые зависят друг от друга, у вас есть два варианта:

  • Поместить их в одну единицу трансляции.
  • Преобразуйте их в статические функциональные переменные, извлекаемые и создаваемые при первом использовании.

Пример 1: глобальный конструктор A использует глобальный журнал

class AType
{    AType()  { log.report("A Constructed");}};

LogType    log;
AType      A;

// Or 
Class AType() 
{    AType()  { getLog().report("A Constructed");}};
LogType& getLog()
{
    static LogType  log;
    return log;
}
// Define A anywhere;

Пример Глобальный деструктор B использует глобальный журнал

Здесь вы должны разрешить, что журнал объекта не уничтожается до объекта B. Это означает, что журнал должен быть полностью построен до объекта B (в этом случае будет применяться правило обратного порядка уничтожения). Опять же, можно использовать те же методы. Либо поместите их в ту же единицу перевода, либо используйте функцию для получения журнала.

class BType
{    ~BType()  { log.report("B Destroyed");}};

LogType    log;
BType      B;   // B constructed after log (so B will be destroyed first)

// Or 
Class BType() 
{    BType()    { getLog();}
     /*
      * If log is used in the destructor then it must not be destroyed before B
      * This means it must be constructed before B 
      * (reverse order destruction guarantees that it will then be destroyed after B)
      *
      * To achieve this just call the getLog() function in the constructor.
      * This means that 'log' will be fully constructed before this object.
      * This means it will be destroyed after and thus safe to use in the destructor.
      */
    ~BType()    { getLog().report("B Destroyed");}
};
LogType& getLog()
{
    static LogType  log;
    return log;
}
// Define B anywhere;
6
ответ дан 28 November 2019 в 23:13
поделиться

Это зависит не от ОС, а от ее компилятора.

Вы дали ответ, инициализация выполняется в __ init .

Для второй части в gcc вы можете гарантировать порядок инициализации с помощью атрибута ____ ____ ((init_priority (PRIORITY) )) , прикрепленный к определению переменной, где PRIORITY - некоторое относительное значение, сначала инициализируются меньшие числа.

11
ответ дан 28 November 2019 в 23:13
поделиться

Согласно стандарту C ++ они вызываются перед использованием какой-либо функции или объекта их единицы перевода. Обратите внимание, что для объектов в глобальном пространстве имен это будет означать, что они инициализируются до вызова main () . (См. Ответы ltcmelo и ] Мартина для получения более подробной информации и обсуждения этого.)

5
ответ дан 28 November 2019 в 23:13
поделиться
Другие вопросы по тегам:

Похожие вопросы: