OK, mal ein Beispiel:
|
C-/C++-Quelltext
|
1
2
3
4
5
6
7
|
{
EineKlasse instanz;
irgendNeFunktion();
... // mach was mit der 'instanz'
}
|
|
C-/C++-Quelltext
|
1
2
3
4
5
6
7
8
9
|
{
EineKlasse * zeigerAufInstanz = new EineKlasse;
irgendNeFunktion();
... // mach was mit der 'instanz'
delete zeigerAufInstanz;
}
|
Scheinz gleichwertig, nur das die zweite Variante mehr Code umfast. Falsch gedacht. Der Aufruf von "irgendNeFunktion" ist ja nicht umsonst da.
Diese Funktion könnte ne Exception werfen. Die erste Variante hätte damit keine Probleme, bei der zweiten hätten wir mindestens ein Memory-Leak. Vielleicht bleiben auch Dateien offen oder sogar Datenbankanbindungen und was weiß ich nicht noch alles, nur weil das Objekt nicht ordnungsgemäß zerstört wurde.
Jetzt könnte man auf die Idee kommen einen try-Block um den Funktionsaufruf zu schreiben:
|
C-/C++-Quelltext
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
{
EineKlasse * zeigerAufInstanz = new EineKlasse;
try {
irgendNeFunktion();
}
catch (...) {
delete zeigerAufInstanz;
throw;
}
... // mach was mit der 'instanz'
delete zeigerAufInstanz;
}
|
Aber jetzt stelle man sich mal vor, man würde nicht nur eine Funktion aufrufen sonderen mehrere und man würde in der Funktion nicht nur ein Objekt erstellen, sondern mehrere. Die Funktion würde gigantische Ausmaße annehmen.
Vor allem allein schon wegen sowas:
|
C-/C++-Quelltext
|
1
2
|
Foo * foo = new Foo;
Bar * bar = new Bar;
|
Sollte 'new Bar' eine std::bad_alloc werfen, wer würde dann das von 'foo' referenzierte Objekt freigeben?
Man sieht, das Variante ohne dynamisches Allokieren ganz klar zu bevorzugen ist.
P.S.
Die gezeigten Probleme könnte man auch mit Smart-Pointern umgehen.