В книге Страуструпа ("Язык программирования С++", спец. издание, гл. 21.5.2) приводится способ однократной инициализации библиотеки на основе статического счетчика объектов. Да и здесь эта тема обсуждалась (здесь
class c_some
{
public:
static int x;
c_some(void);
};
[some.cpp]
#include"some.h"int c_some::x = 0;
c_some::c_some(void)
{
// использование x
}
[test.cpp]
#include"some.h"
c_some some;
Вопрос — а где гарантия, что c_some::x будет инициализирован до создания первого объекта c_some?
Что происходит, если первый объект c_some также создается глобально, или в конструкторе глобального объекта другого класса? Получается, что для того, чтобы этот прием работал, должен быть определенный порядок инициализации —
int c_some::x = 0 (some.cpp) должно выполниться раньше, чем c_some some (test.cpp).
Это что же, линкер должен соответствующим образом разместить данные в .cinit, или как вообще?
Здравствуйте, KPavel, Вы писали:
KP>Всем привет!
KP>В книге Страуструпа ("Язык программирования С++", спец. издание, гл. 21.5.2) приводится способ однократной инициализации библиотеки на основе статического счетчика объектов. Да и здесь эта тема обсуждалась (здесь
KP>#include"some.h"
KP>int c_some::x = 0;
KP>c_some::c_some(void)
KP>{
KP> // использование x
KP>}
KP>
KP>[test.cpp]
KP>
KP>#include"some.h"
KP>c_some some;
KP>
KP>Вопрос — а где гарантия, что c_some::x будет инициализирован до создания первого объекта c_some?
KP>Что происходит, если первый объект c_some также создается глобально, или в конструкторе глобального объекта другого класса? Получается, что для того, чтобы этот прием работал, должен быть определенный порядок инициализации - KP>int c_some::x = 0 (some.cpp) должно выполниться раньше, чем c_some some (test.cpp). KP>Это что же, линкер должен соответствующим образом разместить данные в .cinit, или как вообще?
KP>
Если у тебя 2 статических или глобальных объекта в разных единицах компиляции то нет никакой гарантии в порядке создания объектов.
Здравствуйте, KPavel, Вы писали:
K> В книге Страуструпа ("Язык программирования С++", спец. издание, гл. K> 21.5.2) приводится способ однократной инициализации библиотеки на K> основе статического счетчика объектов.
K>
K> int c_some::x = 0;
K>
K> Вопрос — а где гарантия, что c_some::x будет инициализирован до K> создания первого объекта c_some?
Статическая инициализация всегда выполняется до динамической. Инициализация конструктором
или результатом функции — динамическая инициализация, константой — статическая.
Posted via RSDN NNTP Server 1.6 RC1
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
KP>> #include"some.h"
KP>> int c_some::x = 0;
KP>> c_some::c_some(void)
KP>> {
KP>> // использование x
KP>> }
KP>>
Y> Если у тебя 2 статических или глобальных объекта в разных единицах Y> компиляции то нет никакой гарантии в порядке создания объектов.
Кроме того, что статическая инициализация будет выполнена раньше динамической.
В данном случае этого достаточно, т.к. ни один конструктор c_some не может
быть вызван до выполнения статической инициализации.
Posted via RSDN NNTP Server 1.6 RC1
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Здравствуйте, KPavel, Вы писали:
KP>Вопрос — а где гарантия, что c_some::x будет инициализирован до создания первого объекта c_some?
Нет. Но если очень надо то можно так
class c_some
{
public:
static int& x()
{
static int x_=0;
return x_;
}
c_some(void)
{
//использование x()
}
};
... << RSDN@Home 1.1 alpha 1 >>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Здравствуйте, KPavel, Вы писали:
KP>В книге Страуструпа ("Язык программирования С++", спец. издание, гл. 21.5.2) приводится способ однократной инициализации библиотеки на основе статического счетчика объектов. Да и здесь эта тема обсуждалась (здесь
Здравствуйте, Павел Кузнецов, Вы писали:
ПК>Кроме того, что статическая инициализация будет выполнена раньше динамической. ПК>В данном случае этого достаточно, т.к. ни один конструктор c_some не может ПК>быть вызван до выполнения статической инициализации.
Уверен? А если есть статическая переменная типа c_some?
... << RSDN@Home 1.1 alpha 1 >>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Здравствуйте, WolfHound, Вы писали:
ПК>> Кроме того, что статическая инициализация будет выполнена раньше ПК>> динамической. В данном случае этого достаточно, т.к. ни один ПК>> конструктор c_some не может быть вызван до выполнения статической ПК>> инициализации.
W> Уверен? А если есть статическая переменная типа c_some?
То она будет проинициализирована вызовом конструктора, т.е. это уже динамическая инициализация.
А инициализация переменной типа int константным выражением — статическая.
3.6.2 Initialization of non-local objects
1 The storage for objects with static storage duration (3.7.1) shall be zero-initialized (8.5)
before any other initialization takes place. Zero-initialization and initialization with a constant
expression are collectively called static initialization; all other initialization is dynamic
initialization. Objects of POD types (3.9) with static storage duration initialized with constant
expressions (5.19) shall be initialized before any dynamic initialization takes place.
Posted via RSDN NNTP Server 1.6 RC1
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Здравствуйте, Павел Кузнецов, Вы писали:
W>> Уверен? А если есть статическая переменная типа c_some? ПК>То она будет проинициализирована вызовом конструктора, т.е. это уже динамическая инициализация. ПК>А инициализация переменной типа int константным выражением — статическая.
В этом случае да. Но если это не int и компания то...
... << RSDN@Home 1.1 alpha 1 >>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Во-первых, большое спасибо Павлу Кузнецову за исчерпывающий ответ.
У меня есть еще несколько вопросов на эту тему.
Определяется ли порядок разрушения статических и глобальных объектов порядком инициализации? Если да,
то как — LIFO?
Когда происходит инициализация статического объекта, определенного в функции — при первом вызове функции,
или в порядке общей очереди при инициализации глобальных объектов и статических членов-объектов классов?
Различает ли стандарт глобальные переменные/статические члены/статические переменные функций при инициализации
и разрушении?
Здравствуйте, KPavel, Вы писали:
K> Определяется ли порядок разрушения статических и глобальных объектов K> порядком инициализации? Если да, то как — LIFO?
Именно так. При этом, гарантируется, что разрушение будет происходить именно в таком порядке,
независимо от того, в каких единицах трансляции определены объекты.
K> Когда происходит инициализация статического объекта, определенного в функции - K> при первом вызове функции, или в порядке общей очереди при инициализации глобальных K> объектов и статических членов-объектов классов?
Ответ на этот вопрос зависит от того, что за объект и как именно он проинициализирован. Сначала, до любой
другой инициализации, производится инициализация нулями. Инициализация объектов POD-типа (например, int),
проиинициализировнных константными выражениями, выполняется до того, как управление попадает в блок, где
они определены. Точный момент не известен, но это и не нужно. Остальные объекты, если реализация может
инициализировать их статически, могут инициализироваться по правилам инициализации объектов, определенных
вне функций (namespace scope). Фактически, статическая инициализация обычно означает заполнение
соответствующего сегмента данных соответствующими значениями еще при загрузке программы. Прочие объекты,
например, инициализирующиеся вызовом функции или конструктором, должны быть проинициализированы не просто
при первом вызове, а именно в момент, когда управление проходит через точку, в которой определен искомый
объект. Например:
struct C {
C();
~C();
};
void f(int i)
{
if (i < 1)
return;
static C c1;
if (i < 2)
return;
static C c2;
}
int main()
{
f(0);
f(1);
f(2);
}
Если инициализация c1 и c2 не будет заменена на статическую (а скорее всего, не будет, т.к. определение
C::C() находится в другой единице трансляции), то при вызове f(0) не будет проинициализирован ни c1, ни
с2. При вызове f(1) будет проинициализирован только c1. При вызове f(2) — только c2, т.к. c1 уже
проинициализирован ранее.
K> Различает ли стандарт глобальные переменные/статические члены/статические переменные функций при инициализации и разрушении?
Как видишь, объекты со статическим временем жизни, определенные в функциях, различает Глобальные
переменные и статические члены классов в этом отношении не различаются.
Posted via RSDN NNTP Server 1.6 RC1
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Здравствуйте, Павел Кузнецов, Вы писали:
K>> Определяется ли порядок разрушения статических и глобальных объектов K>> порядком инициализации? Если да, то как — LIFO?
ПК>Именно так. При этом, гарантируется, что разрушение будет происходить именно в таком порядке, ПК>независимо от того, в каких единицах трансляции определены объекты.
Это относится и к статическим объектам, определенным в функциях? Я попробовал сделать следующее:
Расставил breakpoints. Конструкторы вызываются в таком порядке: c_some, c_resource.
Деструкторы — точно так же: ~c_some, ~c_resource.
Почему так, ведь resource инициализировался после начала инициализации some? Должна ли
реализация фиксировать очередность по моментам окончания инициализации объектов? В принципе, мне
такое поведение как раз и нужно.
Здравствуйте, KPavel, Вы писали:
K> Расставил breakpoints. Конструкторы вызываются в таком порядке: K> c_some, c_resource. Деструкторы — точно так же: ~c_some, ~c_resource.
K> Почему так, ведь resource инициализировался после начала K> инициализации some? Должна ли реализация фиксировать K> очередность по моментам окончания инициализации объектов? K> В принципе, мне такое поведение как раз и нужно.
Именно так и должно быть. Порядок разружения объектов определяется порядком завершения конструкторов.
Posted via RSDN NNTP Server 1.6 RC1
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен