Das Folgende ist natürlich alles nicht ganz genau. Nimm es mit einem Körnchen Salz, wenn du es liest :)
Nun, die drei Dinge, auf die Sie sich beziehen, sind die automatische, statische und dynamische Speicherdauer , die etwas damit zu tun hat, wie lange Objekte leben und wann sie zu leben beginnen.
Automatische Speicherdauer
Sie verwenden die automatische Speicherdauer für kurzlebige und kleine Daten, die nur lokal innerhalb eines Blocks benötigt werden:
if(some condition) {
int a[3]; // array a has automatic storage duration
fill_it(a);
print_it(a);
}
Die Lebensdauer endet, sobald wir den Block verlassen, und sie beginnt, sobald das Objekt definiert ist. Sie sind die einfachste Art der Speicherdauer und viel schneller als insbesondere die dynamische Speicherdauer.
Statische Speicherdauer
Sie verwenden die statische Speicherdauer für freie Variablen, auf die jeder Code jederzeit zugreifen kann, wenn ihr Gültigkeitsbereich eine solche Verwendung zulässt (Namespace-Gültigkeitsbereich), und für lokale Variablen, die ihre Lebensdauer über den Exit ihres Gültigkeitsbereichs verlängern müssen (lokaler Gültigkeitsbereich) für Mitgliedsvariablen, die von allen Objekten ihrer Klasse gemeinsam genutzt werden müssen (Klassenbereich). Ihre Lebensdauer hängt von dem Bereich ab, in dem sie sich befinden. Sie können einen Namespace-Bereich sowie einen lokalen Bereich und einen Klassenbereich haben . Was für beide gilt, ist, dass, sobald ihr Leben beginnt, das Leben am Ende des Programms endet . Hier sind zwei Beispiele:
// 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;
}
Das Programm wird gedruckt ababab
, da localA
es beim Verlassen seines Blocks nicht zerstört wird. Sie können sagen, dass Objekte mit lokalem Gültigkeitsbereich ihre Lebensdauer beginnen, wenn die Steuerung ihre Definition erreicht . Denn localA
es passiert, wenn der Körper der Funktion eingegeben wird. Bei Objekten im Namespace-Bereich beginnt die Lebensdauer beim Programmstart . Gleiches gilt für statische Objekte im Klassenbereich:
class A {
static string classScopeA;
};
string A::classScopeA;
A a, b; &a.classScopeA == &b.classScopeA == &A::classScopeA;
Wie Sie sehen, classScopeA
ist nicht an bestimmte Objekte seiner Klasse gebunden, sondern an die Klasse selbst. Die Adresse aller drei oben genannten Namen ist dieselbe und alle bezeichnen dasselbe Objekt. Es gibt spezielle Regeln darüber, wann und wie statische Objekte initialisiert werden, aber wir wollen uns jetzt nicht darum kümmern. Das ist mit dem Begriff Fiasko der statischen Initialisierungsreihenfolge gemeint .
Dynamische Speicherdauer
Die letzte Speicherdauer ist dynamisch. Sie verwenden es, wenn Objekte auf einer anderen Insel leben sollen, und wenn Sie Zeiger um diese Referenz setzen möchten. Sie verwenden sie auch, wenn Ihre Objekte groß sind und wenn Sie Arrays mit einer Größe erstellen möchten, die nur zur Laufzeit bekannt ist . Aufgrund dieser Flexibilität sind Objekte mit dynamischer Speicherdauer kompliziert und langsam zu verwalten. Objekte mit dieser dynamischen Dauer beginnen ihre Lebensdauer, wenn ein geeigneter neuer Operatoraufruf erfolgt:
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();
}
Seine Lebensdauer endet nur, wenn Sie delete für sie aufrufen . Wenn Sie das vergessen, beenden diese Objekte niemals ihre Lebensdauer. Bei Klassenobjekten, die einen vom Benutzer deklarierten Konstruktor definieren, werden die Destruktoren nicht aufgerufen. Objekte mit dynamischer Speicherdauer erfordern eine manuelle Behandlung ihrer Lebensdauer und der zugehörigen Speicherressource. Es gibt Bibliotheken, um die Verwendung zu vereinfachen. Die explizite Speicherbereinigung für bestimmte Objekte kann mithilfe eines intelligenten Zeigers eingerichtet werden:
int main() {
shared_ptr<string> s(new string);
foo(s);
}
void foo(shared_ptr<string> s) {
cout << s->size();
}
Sie müssen sich nicht darum kümmern, delete aufzurufen: Der freigegebene ptr erledigt dies für Sie, wenn der letzte Zeiger, der auf das Objekt verweist, den Gültigkeitsbereich verlässt. Der gemeinsam genutzte ptr selbst hat eine automatische Speicherdauer. Daher wird seine Lebensdauer automatisch verwaltet, sodass geprüft werden kann, ob das auf ein dynamisches Objekt gerichtete Objekt in seinem Destruktor gelöscht werden soll. Eine Referenz zu shared_ptr finden Sie in den Boost-Dokumenten: http://www.boost.org/doc/libs/1_37_0/libs/smart_ptr/shared_ptr.htm