Poniższe informacje są oczywiście niezupełnie dokładne. Czytając to traktuj to z przymrużeniem oka :)
Cóż, trzy rzeczy, o których mówisz, to automatyczny, statyczny i dynamiczny czas przechowywania , który ma coś wspólnego z tym, jak długo obiekty żyją i kiedy zaczynają życie.
Automatyczny czas przechowywania
Używasz automatycznego czasu przechowywania dla krótkotrwałych i małych danych, które są potrzebne tylko lokalnie w pewnym bloku:
if(some condition) {
int a[3]; // array a has automatic storage duration
fill_it(a);
print_it(a);
}
Okres istnienia kończy się, gdy tylko wyjdziemy z bloku i zaczyna się, gdy tylko obiekt zostanie zdefiniowany. Są to najprostsze rodzaje czasu przechowywania i są znacznie szybsze niż w szczególności dynamiczny czas przechowywania.
Statyczny czas przechowywania
Używasz statycznego czasu przechowywania dla wolnych zmiennych, do których może mieć dostęp dowolny kod przez cały czas, jeśli ich zakres pozwala na takie użycie (zakres przestrzeni nazw), oraz dla zmiennych lokalnych, które wymagają przedłużenia czasu życia poprzez wyjście z ich zakresu (zakres lokalny), oraz dla zmiennych składowych, które muszą być współużytkowane przez wszystkie obiekty swojej klasy (zakres klas). Ich trwałość zależy od zakresu w którym się znajdują. Mogą one mieć zakres przestrzeni nazw i zakresu lokalnego i zakresu klasy . Prawdą jest, że obaj z nich zaczynają żyć, a kończy się wraz z zakończeniem programu . Oto dwa przykłady:
// static storage duration. in global namespace scope
string globalA;
int main() {
foo();
foo();
}
void foo() {
// static storage duration. in local scope
static string localA;
localA += "ab"
cout << localA;
}
Program drukuje ababab
, ponieważ localA
nie jest niszczony po wyjściu z jego bloku. Można powiedzieć, że obiekty o zasięgu lokalnym rozpoczynają okres istnienia, gdy kontrola osiągnie swoją definicję . Na localA
to się dzieje, gdy ciało funkcja jest wpisany. W przypadku obiektów w zakresie przestrzeni nazw okres istnienia rozpoczyna się podczas uruchamiania programu . To samo dotyczy statycznych obiektów o zasięgu klasowym:
class A {
static string classScopeA;
};
string A::classScopeA;
A a, b; &a.classScopeA == &b.classScopeA == &A::classScopeA;
Jak widać, classScopeA
nie jest powiązany z określonymi obiektami swojej klasy, ale z samą klasą. Adres wszystkich trzech powyższych nazw jest taki sam i wszystkie oznaczają ten sam obiekt. Istnieją specjalne zasady dotyczące tego, kiedy i jak inicjowane są obiekty statyczne, ale nie przejmujmy się tym teraz. Oznacza to termin fiasko kolejności inicjalizacji statycznej .
Dynamiczny czas przechowywania
Ostatni okres przechowywania jest dynamiczny. Używasz go, jeśli chcesz, aby obiekty żyły na innej wyspie i chcesz umieścić wskaźniki wokół tych obiektów. Używasz ich również, jeśli twoje obiekty są duże i jeśli chcesz tworzyć tablice o rozmiarze znanym tylko w czasie wykonywania . Z powodu tej elastyczności obiekty o dynamicznym czasie trwania są skomplikowane i powolne w zarządzaniu. Obiekty mające ten dynamiczny czas trwania rozpoczynają okres istnienia, gdy nastąpi odpowiednie wywołanie nowego operatora:
int main() {
// the object that s points to has dynamic storage
// duration
string *s = new string;
// pass a pointer pointing to the object around.
// the object itself isn't touched
foo(s);
delete s;
}
void foo(string *s) {
cout << s->size();
}
Jego żywotność kończy się tylko wtedy, gdy wywołasz ich usunięcie . Jeśli o tym zapomnisz, te obiekty nigdy nie kończą swojego życia. A obiekty klas, które definiują konstruktor zadeklarowany przez użytkownika, nie będą miały wywoływanych destruktorów. Obiekty o dynamicznym czasie trwania wymagają ręcznej obsługi ich okresu istnienia i skojarzonego zasobu pamięci. Biblioteki istnieją po to, aby ułatwić z nich korzystanie. Jawne wyrzucanie elementów bezużytecznych dla określonych obiektów można ustalić za pomocą inteligentnego wskaźnika:
int main() {
shared_ptr<string> s(new string);
foo(s);
}
void foo(shared_ptr<string> s) {
cout << s->size();
}
Nie musisz przejmować się wywołaniem funkcji delete: udostępniony ptr robi to za Ciebie, jeśli ostatni wskaźnik, który odwołuje się do obiektu, znajdzie się poza zakresem. Sam udostępniony plik ptr ma automatyczny czas trwania. Więc jego żywotność jest automatycznie zarządzana, co pozwala mu sprawdzić, czy powinien usunąć wskazany dynamiczny obiekt w swoim destruktorze. Aby uzyskać informacje o shared_ptr, zobacz dokumenty boost: http://www.boost.org/doc/libs/1_37_0/libs/smart_ptr/shared_ptr.htm