Область действия члена данных статического класса

Если у меня есть класс:

Object.h

class Object
{
public:
    static int number;
};

Object.cpp

int Object::number = 5;

Гарантируется ли, что область действия Object::number переживет область действия любого созданного экземпляра Object? даже если он объявлен глобально в другом исходном файле?


person CuriousGeorge    schedule 01.03.2013    source источник
comment
Связь статики класса и нестатических экземпляров преднамеренна и различна. Object::number будет существовать даже тогда, когда никаких экземпляров Object не существует, не говоря уже о том, что они переживут любой конкретный экземпляр Object. Есть только один (если это не шаблон, но технически это не тот же класс, так как это будет сгенерированный вывод).   -  person WhozCraig    schedule 01.03.2013
comment
Кстати, то, о чем вы спрашиваете, называется сроком службы, а не областью действия. Область видимости — это часть исходного файла, в которой видно имя. Время жизни — это период во время выполнения, когда объект существует.   -  person Steve Jessop    schedule 01.03.2013
comment
@WhozCraig: С другой стороны, я считаю, что можно создать и использовать экземпляр Object до того, как Object::number будет инициализирован...   -  person Mooing Duck    schedule 01.03.2013
comment
@MooingDuck - я думаю, это отвечает на точный вопрос ОП.   -  person Robᵩ    schedule 01.03.2013
comment
@MooingDuck Мне пришлось бы серьезно погрузиться в время жизни объектов, глобальные инициализации и определения их формата в стандарте, прежде чем я смог бы подтвердить или опровергнуть, что это возможно, но меня ничуть не удивило бы, если бы это было так. Глобальная инициализация для меня всегда ненадежная вещь, поэтому я стараюсь ее избегать.   -  person WhozCraig    schedule 01.03.2013


Ответы (5)


Рассмотрим эту программу g++:

#include <iostream>
#define X() (std::cout << __PRETTY_FUNCTION__ << "\n")

struct M {
 M() { X(); }
 ~M() { X(); }
};  

struct C {
 C() { X(); }
 ~C() { X(); }
 static M m;
};
C c;
M C::m;
int main () { X(); }

В этой программе c должен быть инициализирован до C::m и должен быть удален после C::m. Если вы скомпилируете эту программу и рассмотрите ее вывод, вы увидите что-то вроде:

C::C()
M::M()
int main()
M::~M()
C::~C()

Итак, нет, в целом, «[срок жизни] [члена]» не «гарантированно превосходит [срок службы] любого созданного экземпляра объекта?»

person Robᵩ    schedule 01.03.2013
comment
Я тоже так думал, но Майк Сеймур отмечает, что есть особый случай для объектов, которые имеют constexpr конструкторы и примитивы: § 3.6.2/2 - person Mooing Duck; 01.03.2013
comment
Правильно, так что конкретно у OP есть гарантия для Object, описанного в вопросе. Но в целом на все остальные виды объектов у него нет такой гарантии. - person Robᵩ; 01.03.2013

Да, он имеет «статическую продолжительность хранения», что означает, что он существует «все время» [если у него есть нестандартный конструктор, конструктор вызывается перед запуском «основного» — этого должно быть достаточно для большинства намерений и целей]

person Mats Petersson    schedule 01.03.2013
comment
Он может существовать, но не может быть инициализирован до ожидаемого вами значения. - person Mooing Duck; 01.03.2013

Вроде того, но только потому, что int — особый случай. Например, предположим, что вы пишете в Object.cpp:

Object o = {};
int Object::number = 5;

Тогда объект o имеет статическую продолжительность хранения, как и Object::number. Номинально он создается до number и будет уничтожен позже, но, поскольку они оба являются POD, это уничтожение фактически не имеет никакого эффекта.

Однако если бы number и o имели нетривиальные деструкторы, то number был бы уничтожен до o. Тот факт, что number является статическим членом класса o, не дает ему особого отношения к порядку уничтожения.

Если o выключен в другом исходном файле, то порядок построения не указан, а порядок уничтожения является обратным порядком построения (опять же, это если у них были нетривиальные деструкторы - int является особым случаем, поскольку это не так).

person Steve Jessop    schedule 01.03.2013

Да, по двум причинам:

  • Он имеет статическую продолжительность хранения, поэтому его хранение длится в течение всего времени жизни программы.
  • У него есть тип без конструктора, инициализированный константным выражением.

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

Если бы у него был конструктор или непостоянный инициализатор, то он был бы инициализирован во время динамической инициализации вместе со всеми другими такими объектами. В этом случае конструктор или инициализатор другого статического объекта может получить доступ к объекту до его инициализации. Эту проблему иногда называют «фиаско статического порядка инициализации».

person Mike Seymour    schedule 01.03.2013

Стандарт гарантирует, что объекты с длительностью статического хранения существуют в течение всего времени работы программы.

C++03, 3.7.1 Длительность статического хранения §1:

Все объекты, которые не имеют динамической продолжительности хранения и не являются локальными, имеют статическую продолжительность хранения. Хранилище для этих объектов должно длиться в течение всего срока действия программы.

и в вашем примере также актуален §4:

Ключевое слово static, примененное к члену данных класса в определении класса, дает срок статического хранения члена данных.

person LihO    schedule 01.03.2013
comment
Он может существовать, но не может быть инициализирован до ожидаемого вами значения. - person Mooing Duck; 01.03.2013