Каково время жизни статических переменных класса в С++?

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

class Test
{
    static std::vector<int> staticVector;
};

когда создается staticVector и когда он уничтожается?

Это с созданием первого объекта класса Test или как обычные статические переменные?

Просто чтобы уточнить, этот вопрос пришел мне в голову после прочтения «Концепции языков программирования» (Sebesta Ch-5.4.3.1), и он говорит::

Обратите внимание, что когда модификатор static появляется в объявлении переменной в определении класса в C++, Java и C#, он не имеет ничего общего со временем жизни переменной. В этом контексте это означает, что переменная является переменной класса, а не переменной экземпляра. Многократное использование зарезервированного слова может сбивать с толку, особенно тех, кто изучает язык.

Вы поняли? :(


person AraK    schedule 03.07.2009    source источник


Ответы (5)


Точно так же, как обычные статические (глобальные) переменные.

person Magnus Hoff    schedule 03.07.2009
comment
Единственный момент, который следует отметить в дополнение к этому, заключается в том, что порядок построения статических/глобальных переменных не определен. - person Skizz; 03.07.2009
comment
Я бы также добавил, что именно так создаются переменные в любых пространствах имен. Глобальные и неглобальные (например, std::cout). - person Johannes Schaub - litb; 03.07.2009
comment
@skizz: в конкретной единице компиляции порядок четко определен как порядок объявления. В нескольких единицах компиляции он не определен (или не указан). Но вопрос в разрушении. - person Martin York; 03.07.2009
comment
Порядок уничтожения статических/глобальных переменных является порядком, обратным их созданию. - person Martin York; 03.07.2009
comment
Некоторые придирки, но важные придирки: порядок зависит от их порядка определения, а не порядка их объявления: в следующем коде a создается после b, даже если a объявлено до b: extern A a; B b(a); A a; — этот код может дать удивительные результаты. - person Johannes Schaub - litb; 03.07.2009

Я также хочу написать текст об инициализации, на который я могу позже сослаться.


Сначала список возможностей.

  • Пространство имен Статическое
  • Класс Статический
  • Локальный Статический

Статическое пространство имен

  • Существует два метода инициализации. статическая (должна выполняться во время компиляции) и динамическая (должна выполняться во время выполнения) инициализация.
  • Статическая инициализация происходит до любой динамической инициализации, независимо от отношений единиц трансляции.
  • Динамическая Инициализация упорядочена в единице перевода, в то время как в статической инициализации нет определенного порядка. Объекты пространства имен одной и той же единицы трансляции динамически инициализируются в том порядке, в котором появляется их определение.
  • Объекты типа POD, которые инициализируются константными выражениями, инициализируются статически. На их значение можно положиться при динамической инициализации любого объекта, независимо от отношений единиц трансляции.
  • Если инициализация выдает исключение, вызывается std::terminate.

Примеры:

Следующая программа печатает A(1) A(2)

struct A { 
  A(int n) { std::printf(" A(%d) ", n); } 
};

A a(1);
A b(2);

А следующее, основанное на том же классе, печатает A(2) A(1)

extern A a;
A b(2);
A a(1);

Предположим, что есть единица перевода, где msg определяется следующим образом:

char const *msg = "abc";

Затем выводится следующее: abc. Обратите внимание, что p получает динамическую инициализацию. Но поскольку статическая инициализация (char const* — это тип POD, а "abc" — адресное постоянное выражение) msg происходит до этого, это нормально, и msg гарантированно будет правильно инициализирован.

extern const char *msg;
struct P { P() { std::printf("%s", msg); } };
P p;
  • Динамическая инициализация объекта не обязательно должна происходить до main любой ценой. Однако инициализация должна произойти до первого использования объекта или функции его единицы перевода. Это важно для динамически загружаемых библиотек.

Статический класс

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

Локальный статический

  • Для локальной статики бывают особые правила.
  • Объекты типа POD, инициализированные константным выражением, инициализируются перед входом в их блок, в котором они определены.
  • Другие локальные статические объекты инициализируются при первом прохождении управления через их определение. Инициализация не считается завершенной, когда возникает исключение. Инициализация будет предпринята снова в следующий раз.

Пример. Следующая программа печатает 0 1:

struct C { 
  C(int n) { 
    if(n == 0)
      throw n;
    this->n = n;
  }
  int n;
};

int f(int n) {
  static C c(n);
  return c.n;
}

int main() {
  try { 
    f(0); 
  } catch(int n) { 
    std::cout << n << " "; 
  }
  f(1); // initializes successfully
  std::cout << f(2);  
}

Во всех вышеперечисленных случаях, в некоторых ограниченных случаях, для некоторых объектов, которые не требуют статической инициализации, компилятор может инициализировать их статически, а не динамически. Это сложная проблема, см. va/921681#921681">этот ответ для более подробного примера.

Также обратите внимание, что порядок разрушения является точным порядком завершения строительства объектов. Это обычное дело и происходит во всех ситуациях в C++, в том числе при уничтожении временных файлов.

person Johannes Schaub - litb    schedule 03.07.2009

Он создается одновременно с созданием и уничтожением глобальных переменных вместе с глобальными переменными.

person Goz    schedule 03.07.2009
comment
Никакие статические функциональные переменные не создаются при первом использовании. Если они не используются, то они никогда не создаются. Кроме того, поскольку они создаются при первом использовании, их порядок зависит от порядка вызова функций/методов. - person Martin York; 03.07.2009
comment
Да, но он не спрашивал о переменных статической функции... но да... вы правы. - person Goz; 04.07.2009

Проще говоря:
Статическая переменная-член создается при создании глобальных переменных. Порядок построения глобальных переменных не определен, но это происходит до входа в main-функцию.

Разрушение происходит, когда уничтожаются глобальные переменные.

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

С уважением,
Ованес

P.S.: Я предлагаю взглянуть на C++-Standard, который объясняет (определяет), как и когда создаются или уничтожаются глобальные или статические переменные-члены.

PPS: Ваш код только объявляет статическую переменную-член, но не инициализирует ее. Для его инициализации вы должны написать в одном из модулей компиляции:

std::vector Test::staticVector;
or
std::vector Test::staticVector=std::vector(/* здесь параметры ctor */);

person ovanes    schedule 03.07.2009

Некоторая конкретная информация о VC++ на случай, если вы ее используете:

  1. Построение статических переменных класса происходит одновременно с другими статическими/глобальными переменными.
  2. В windows за эту конструкцию отвечает функция запуска CRT. Это фактическая точка входа большинства программ, которые вы компилируете (это функция, которая вызывает вашу функцию Main/Winmain). Кроме того, он отвечает за инициализацию всей поддержки среды выполнения C (например, вам нужно использовать malloc).
  3. Порядок построения не определен, однако при использовании компилятора Microsoft VC порядок построения для базовых типов будет в порядке, например, это законно и безопасно писать

statics.h: ... объявление MyClass ... static const int a; статический интервал b; статический интервал []; } static.cpp:

const int MyClass::a = 2;
int MyClass::b = a+3;
int MyClass::ar[a] = {1,2}
person Danra    schedule 03.07.2009
comment
Вопрос относится к C++, а не к Visual C++ или Windows. Последние версии MSVC довольно стандартны, но вы не можете использовать один компилятор в качестве ссылки или доказательства. Стандарт должен быть определенным источником, на который вы должны полагаться. Время жизни глобальных или статических переменных-членов и их инициализация очень хорошо описаны в стандарте. Почему вы используете статический спецификатор для переменных, не являющихся членами? Это заставит их иметь внутреннюю связь! Я думаю, что у вас будут ошибки связывания в других модулях компиляции, таких как statics.cpp. - person ovanes; 03.07.2009