================================= Lebenszeit und -ort eines Objekts [TOC] ================================= Objekte können global bzw. statisch, lokal auf dem Stack oder auf dem Heap leben. Ihre Lebenszeit ist entsprechend. Zusätzlich gibt es auch noch `thread_local`-Deklarationen für Objekte, deren Lebenszeit mit der eines Threads verbunden sind. Damit beschäftigen wir uns aber noch nicht im Rahmen dieser Sitzung. Globale bzw. statische Variablen ================================ Bei globalen bzw. statischen Variablen steht die Adresse beim Zusammenbau des Programms bereits fest (daher _statisch_ im Gegensatz zu _dynamisch_, d.h. zur Laufzeit). Entsprechende Objekte werden vor dem Aufruf von _main_ konstruiert und nach dem Ende von _main_ bzw. dem Aufruf von _exit_ abgebaut. Eine Ausnahme davon sind mit `static` deklarierte Objekte innerhalb einer Funktion oder Methode. Diese werden erst konstruiert, wenn die Ausführung die entsprechende Deklaration das erste Mal erreicht. Dies ist seit C++11 auch _thread-safe_. Alle Deklarationen sind im folgenden Beispiel global bzw. statisch: :import: session02/global.cpp ---- SHELL (path=session02,hostname=theon) --------------- g++ -Wall -o global global.cpp ./global ---------------------------------------------------------- Es ist hier wiederum zu beobachten, dass alle Objekte in umgekehrter Reihenfolge abgebaut werden. Das ist bei innerhalb einer Funktion oder Methode statisch deklarierten Variablen nicht trivial umzusetzen, da die Reihenfolge der Konstruktionen nicht vorhersehbar ist: :import: session02/static-can-be-dynamic.cpp ---- SHELL (path=session02,hostname=theon) --------------- g++ -Wall -o static-can-be-dynamic static-can-be-dynamic.cpp echo 0 | ./static-can-be-dynamic echo 1 | ./static-can-be-dynamic ---------------------------------------------------------- Lokale Variablen ================ Wenn die Programmausführung eine lokale Variablendeklaration erreicht, wird diese konstruiert. Am Ende des umgebenden Blocks (das ist das umgebende _compound statement_) werden die lokalen Variablen in umgekehrter Reihenfolge wieder abgebaut. Alle lokalen Variablen leben in dem entsprechenden Stack-Segment, das dem Funktionsaufruf zugeordnet ist. :import: session02/local.cpp ---- SHELL (path=session02,hostname=theon) --------------- g++ -Wall -o local local.cpp ./local ---------------------------------------------------------- Variablen auf dem Heap ====================== Daten können auf dem Heap mit dem `new`-Operator angelegt werden. Mit `delete` werden sie zunächst dekonstruiert und danach wird der belegte Speicher freigegeben. Bei einem Speicherleck, d.h. dem Fehlen von `delete` kommt es nicht zum Abbau der entsprechenden Objekte. Solche Speicherlecks können mit Hilfe des Werkzeugs _valgrind_ festgestellt werden. :import: session02/heap.cpp [linenumbers] ---- SHELL (path=session02,hostname=theon) --------------- g++ -Wall -Wno-unused-variable -g -o heap heap.cpp ./heap valgrind ./heap valgrind --leak-check=full ./heap ---------------------------------------------------------- Aufgaben ======== * Was gibt folgendes Programm aus? Ist die Reihenfolge der Abbauten genau umgekehrt zur Reihenfolge der Konstruktionen? Wenn nein: Woran liegt das? :import: session02/case05.cpp * Ergänzen Sie die folgende Vorlage mit der Klasse _Chain_, deren Konstruktor einen Namen und einen Zeiger auf ein nachfolgendes Mitglied erhält. Beim Abbau sollte die Klasse zuerst das nachfolgende Mitglied freigeben und dann die entsprechende Meldung ausgeben. Der Nullzeiger wird in C++ mit `nullptr` bezeichnet und es ist kein Problem, wenn `delete` mit einem Nullzeiger aufgerufen wird. ---- CODE (type=cpp) ------------------------------------------------------- #include class Chain { /* FIXME */ }; int main() { Chain* c1p = new Chain("chain member #1", nullptr); Chain* c2p = new Chain("chain member #2", c1p); Chain* c3p = new Chain("chain member #3", c2p); delete c3p; } ---------------------------------------------------------------------------- Erwartete Ausgabe: ---- CODE (type=txt) ------------------------------------------------------- Chain "chain member #1" constructed Chain "chain member #2" constructed Chain "chain member #3" constructed Chain "chain member #1" destructed Chain "chain member #2" destructed Chain "chain member #3" destructed ---------------------------------------------------------------------------- Was wäre in der Klasse _Chain_ zu ändern, damit die Abbau-Meldungen in der umgekehrten Reihenfolge erscheinen? :navigate: up -> doc:index back -> doc:session02/page02 next -> doc:session02/page04