Инициализация статических членов
От: KPavel Россия  
Дата: 25.07.03 17:39
Оценка:
Всем привет!

В книге Страуструпа ("Язык программирования С++", спец. издание, гл. 21.5.2) приводится способ однократной инициализации библиотеки на основе статического счетчика объектов. Да и здесь эта тема обсуждалась (здесь
Автор: Курилка
Дата: 12.02.02
).

Допустим:

[some.h]

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, или как вообще?
Re: Инициализация статических членов
От: Yacha Россия  
Дата: 25.07.03 17:46
Оценка:
Здравствуйте, KPavel, Вы писали:

KP>Всем привет!


KP>В книге Страуструпа ("Язык программирования С++", спец. издание, гл. 21.5.2) приводится способ однократной инициализации библиотеки на основе статического счетчика объектов. Да и здесь эта тема обсуждалась (здесь
Автор: Курилка
Дата: 12.02.02
).


KP>Допустим:


KP>[some.h]


KP>
KP>class c_some
KP>{
KP>    public:
KP>         static int x;
KP>         c_some(void);
KP>};
KP>


KP>[some.cpp]


KP>
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 статических или глобальных объекта в разных единицах компиляции то нет никакой гарантии в порядке создания объектов.
... << RSDN@Home 1.0 beta 6a >>
Re: Инициализация статических членов
От: Павел Кузнецов  
Дата: 25.07.03 17:51
Оценка: 12 (3)
Здравствуйте, 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
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[2]: Инициализация статических членов
От: Павел Кузнецов  
Дата: 25.07.03 17:54
Оценка:
Здравствуйте, Yacha, Вы писали:

KP>>
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
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re: Инициализация статических членов
От: WolfHound  
Дата: 25.07.03 18:00
Оценка: 3 (1)
Здравствуйте, 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) А. Эйнштейн
Re: Инициализация статических членов
От: Yacha Россия  
Дата: 25.07.03 18:00
Оценка: 4 (2)
Здравствуйте, KPavel, Вы писали:

KP>В книге Страуструпа ("Язык программирования С++", спец. издание, гл. 21.5.2) приводится способ однократной инициализации библиотеки на основе статического счетчика объектов. Да и здесь эта тема обсуждалась (здесь
Автор: Курилка
Дата: 12.02.02
).


KP>
KP>#include "some.h"

KP>int c_some::x = 0;

KP>c_some::c_some(void)
KP>{
KP>    // использование x
KP>}
KP>


Например, для простого случая зависимости глобальных статических объектов можно сделать так:
class X
{
//...
};

X& GetX()
{
    static X x;
    return x;
}

class Y
{
public:
    Y()
    {
        const X& x = GetX();
        ....
    }
};

namespace
{
    Y theY;
}

....


Так мы сможем гарантировать что X всегда раньше создатся чем Y.
... << RSDN@Home 1.0 beta 6a >>

Удалено избыточное цитирование. -- ПК.
Re[3]: Инициализация статических членов
От: WolfHound  
Дата: 25.07.03 18:01
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>Кроме того, что статическая инициализация будет выполнена раньше динамической.

ПК>В данном случае этого достаточно, т.к. ни один конструктор c_some не может
ПК>быть вызван до выполнения статической инициализации.
Уверен? А если есть статическая переменная типа c_some?
... << RSDN@Home 1.1 alpha 1 >>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[4]: Инициализация статических членов
От: Павел Кузнецов  
Дата: 25.07.03 18:12
Оценка: 3 (1) +1
Здравствуйте, 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
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[5]: Инициализация статических членов
От: WolfHound  
Дата: 25.07.03 18:19
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

W>> Уверен? А если есть статическая переменная типа c_some?

ПК>То она будет проинициализирована вызовом конструктора, т.е. это уже динамическая инициализация.
ПК>А инициализация переменной типа int константным выражением — статическая.
В этом случае да. Но если это не int и компания то...
... << RSDN@Home 1.1 alpha 1 >>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re: Разрушение статических объектов
От: KPavel Россия  
Дата: 26.07.03 09:05
Оценка:
Во-первых, большое спасибо Павлу Кузнецову за исчерпывающий ответ.
У меня есть еще несколько вопросов на эту тему.

Определяется ли порядок разрушения статических и глобальных объектов порядком инициализации? Если да,
то как — LIFO?

Когда происходит инициализация статического объекта, определенного в функции — при первом вызове функции,
или в порядке общей очереди при инициализации глобальных объектов и статических членов-объектов классов?
Различает ли стандарт глобальные переменные/статические члены/статические переменные функций при инициализации
и разрушении?
Разрушение статических объектов
От: Павел Кузнецов  
Дата: 26.07.03 11:10
Оценка: 6 (2)
#Имя: FAQ.cpp.static.destroy
Здравствуйте, 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
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[3]: Разрушение статических объектов
От: KPavel Россия  
Дата: 26.07.03 13:50
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

K>> Определяется ли порядок разрушения статических и глобальных объектов

K>> порядком инициализации? Если да, то как — LIFO?

ПК>Именно так. При этом, гарантируется, что разрушение будет происходить именно в таком порядке,

ПК>независимо от того, в каких единицах трансляции определены объекты.

Это относится и к статическим объектам, определенным в функциях? Я попробовал сделать следующее:

class c_resource
{
    public:
        c_resource(void) 
        {
        }

        ~c_resource(void) 
        {
        }

};

class c_some
{
    public:
        c_some(void);
        ~c_some(void);

    private:
        static c_resource& get_resource(void) 
        {
            static c_resource resource;
            return resource; 
        }

};

c_some::c_some(void)
{
    c_resource& resource = get_resource();
}

c_some::~c_some(void)
{
    c_resource& resource = get_resource();
}

c_some some;

+ пустой main(). Компилятор — VC6.

Расставил breakpoints. Конструкторы вызываются в таком порядке: c_some, c_resource.
Деструкторы — точно так же: ~c_some, ~c_resource.

Почему так, ведь resource инициализировался после начала инициализации some? Должна ли
реализация фиксировать очередность по моментам окончания инициализации объектов? В принципе, мне
такое поведение как раз и нужно.
Re[4]: Разрушение статических объектов
От: Павел Кузнецов  
Дата: 26.07.03 14:14
Оценка:
Здравствуйте, 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
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.