Jestem pewien, że globalnie zadeklarowane zmienne są przydzielane (i inicjowane, jeśli ma to zastosowanie) w czasie uruchamiania programu.
int globalgarbage;
unsigned int anumber = 42;
Ale co ze statycznymi wartościami zdefiniowanymi w funkcji?
void doSomething()
{
static bool globalish = true;
// ...
}
Kiedy jest miejsce na globalish
przydzielenie? Zgaduję, kiedy program się uruchomi. Ale czy wtedy też jest inicjalizowany? Czy jest inicjowany, gdy doSomething()
jest wywoływany po raz pierwszy?
Kilka odpowiednich słów ze standardu C ++:
źródło
If the initialization exits by throwing an exception, the initialization is not complete, so it will be tried again the next time control enters the declaration.
Pamięć dla wszystkich zmiennych statycznych jest przydzielana podczas ładowania programu. Jednak lokalne zmienne statyczne są tworzone i inicjowane przy pierwszym użyciu, a nie podczas uruchamiania programu. Jest kilka dobrych czytanie o tym, i statyki w ogóle tutaj . Ogólnie myślę, że niektóre z tych problemów zależą od implementacji, szczególnie jeśli chcesz wiedzieć, gdzie w pamięci będą znajdować się te rzeczy.
źródło
Kompilator przydzieli statyczne zmienne zdefiniowane w funkcji
foo
podczas ładowania programu, jednak kompilator doda również dodatkowe instrukcje (kod maszynowy) do twojej funkcjifoo
, aby przy pierwszym wywołaniu ten dodatkowy kod zainicjował zmienną statyczną ( np. wywołanie konstruktora, jeśli dotyczy).@Adam: To, za kulisami, wstrzyknięcie kodu przez kompilator jest powodem tego, co zobaczyłeś.
źródło
Próbuję ponownie przetestować kod Adama Pierce'a i dodałem jeszcze dwa przypadki: zmienną statyczną w klasie i typ POD. Mój kompilator to g ++ 4.8.1 w systemie operacyjnym Windows (MinGW-32). Wynik jest zmienna statyczna w klasie jest traktowana tak samo jak zmienna globalna. Jego konstruktor zostanie wywołany przed wejściem do funkcji main.
Wniosek (dla g ++, środowisko Windows):
(1) : Prawidłowym stanem powinno być: „zanim zostanie wywołana jakakolwiek funkcja z tej samej jednostki tłumaczeniowej”. Jednak dla prostoty, jak w przykładzie poniżej, jest to funkcja główna .
include <iostream>
#include < string> using namespace std; class test { public: test(const char *name) : _name(name) { cout << _name << " created" << endl; } ~test() { cout << _name << " destroyed" << endl; } string _name; static test t; // static member }; test test::t("static in class"); test t("global variable"); void f() { static test t("static variable"); static int num = 10 ; // POD type, init before enter main function test t2("Local variable"); cout << "Function executed" << endl; } int main() { test t("local to main"); cout << "Program start" << endl; f(); cout << "Program end" << endl; return 0; }
wynik:
static in class created global variable created local to main created Program start static variable created Local variable created Function executed Local variable destroyed Program end local to main destroyed static variable destroyed global variable destroyed static in class destroyed
Czy ktoś testował w środowisku Linux env?
źródło
Zmienne statyczne są alokowane w segmencie kodu - są częścią obrazu wykonywalnego, a więc są mapowane w już zainicjowanym.
Zmienne statyczne w zakresie funkcji są traktowane tak samo, zakres jest konstrukcją wyłącznie na poziomie języka.
Z tego powodu masz gwarancję, że zmienna statyczna zostanie zainicjowana na 0 (chyba że określisz coś innego) zamiast niezdefiniowanej wartości.
Istnieje kilka innych aspektów inicjalizacji, z których możesz skorzystać - na przykład segmenty współdzielone pozwalają różnym instancjom wykonywanego pliku wykonywalnego jednocześnie na dostęp do tych samych zmiennych statycznych.
W C ++ (o zasięgu globalnym) obiekty statyczne mają swoje konstruktory wywoływane podczas uruchamiania programu, pod kontrolą biblioteki wykonawczej C. W języku Visual C ++ przynajmniej kolejność inicjowania obiektów może być kontrolowana przez pragmę init_seg .
źródło
Tak to jest. Pozwala to między innymi na inicjalizację struktur danych, do których dostęp jest globalny, kiedy jest to stosowne, na przykład wewnątrz bloków try / catch. Np. Zamiast
int foo = init(); // bad if init() throws something int main() { try { ... } catch(...){ ... } }
Możesz pisać
int& foo() { static int myfoo = init(); return myfoo; }
i użyj go wewnątrz bloku try / catch. Przy pierwszym wywołaniu zmienna zostanie zainicjowana. Następnie, przy pierwszym i następnym wywołaniu, jego wartość zostanie zwrócona (przez odniesienie).
źródło