Kurze Frage zu Begriffserklärung ( Von verschiedenen Pointern )
-
Was soll die Funktion denn tun?
-
int *ausgabe ( ) { // Platz für einen int auf dem heap schaffen int* bla = new int; // Irgendwas damit machen *bla = 8; // Pointer zurückgeben return bla; }Der integer auf den bla zeigt wird mit new auf dem heap angelegt. Daher wird er nicht gelöscht wenn der Stack nach abarbeiten der Funktion bereinigt wird.
Du musst dich aber später irgendwo mit delete um die Freigabe dieses Speichers kümmern (sonst Speicherleck!)int* ist eine Adresse. Diese Adresse wird kopiert und zurückgegeben
irgendwo in deinem Programm:
int *blubb = ausgabe(); // gibt "8" aus cout << *blubb << endl; // wenn du den integer nicht mehr brauchst delete blubb;
-
Genau soll man es nicht machen. So hat man es in C gemacht, doch dieser Ansatz ist ganz schön fehleranfällig und in C++ durch RAII abgelöst.
std::auto_ptr<int> ausgabe();Wobei es im Allgemeinen natürlich um komplexere Anwendungen als die Rückgabe eines
ints geht, in denen mehrere Ablaufpfade oder Exceptions die Vorteile von RAII erst richtig zum Vorschein kommen lassen. Hier würde ich einfach einenintals Kopie zurückgeben, das ist ohnehin um einiges schneller.
-
[qoute]
Hier würde ich einfach einen int als Kopie zurückgeben, das ist ohnehin um einiges schneller.
[/quote]Wie meinst du das ?
-
Die dynamische Speicherverwaltung fällt weg.
-
doch dieser Ansatz ist ganz schön fehleranfällig und in C++ durch RAII abgelöst.
Stimmt soweit. Jedoch kann man sich mit auto_ptr (oder auch mit shared_ptr) genauso gut in den Fuß schiessen wie mit new und delete (und meist sind diese Fehler noch schwerer zu debuggen).
-
antialias schrieb:
Jedoch kann man sich mit auto_ptr (oder auch mit shared_ptr) genauso gut in den Fuß schiessen wie mit new und delete (und meist sind diese Fehler noch schwerer zu debuggen).
Kannst du hier etwas konkreter werden (möglichst im Bezug auf beide Smart-Pointer)?
-
Bin halt kein Fan von auto_ptr.
- Die copy-problematik mit STL containern
- dass die sich gegenseitig die Gültigkeit wegschnappen (der Fehler ist mal wirklich schwer zu finden wenn plötzlich ein Pointer seine Gültigkeit verliert ohne dass man ihm irgendwas zugewiesen hat)
- dann kann man ihn nicht auf NULL testen.
.
.
.shared_pointer ist schon besser. Aber wenn man hier vergisst neue Kopien vom shared_pointer zu machen (und sie Anstelle vom Objekt macht), dann kommt das ganze reference counting durcheinander - auch das ist extrem schwer zu debuggen.
Nicht das es mit normalen Pointern leichter ist. Aber wenn ich einen shared_pointer einsetzte dann geh ich halt davon aus, dass er tut was er soll. Sprich: ich such bei Fehler zuletzt beim reference counting mechanismus.
-
Danke für die Ausführungen.
Es stimmt schon, natürlich kann man die Smart-Pointer falsch anwenden. Gerade
std::auto_ptrkann mit seiner Move-Semantik am Anfang verwirrend sein. Aber das sind meiner Meinung nach vor allem Anfängerprobleme, die hauptsächlich aus Unkenntnis der Smart-Pointer und ihrer Besitzsemantik resultieren.Hingegen ist ein sauberes Aufräumen auch für fortgeschrittene Programmierer eine Herausforderung, wenn der Code komplexer wird. Beispiel: Implementiere den folgenden Code ohne Smart-Pointers, sodass er auch im Falle von Exceptions keine Memory Leaks aufweist.
void Function() { scoped_ptr<A> a(new A); scoped_ptr<B> b(new B); scoped_ptr<C> c(new C); if (condition) return; if (otherCondition) throw std::runtime_error("!"); }
-
Übrigens: Folgende Mängel von
std::auto_ptrhaben mich dazu veranlasst, selbst einen verschiebbaren Smart-Pointer zu schreiben:- Deklaration benötigt vollständig definierten Pointee-Typ. Das ist manchmal, besonders in Header-Dateien, eine unnötige Abhängigkeit.
- Tatsächlich kompiliert der Code in meiner Implementierung jedoch auch mit unvollständigem Typ und ruft im Destruktor undefiniertes Verhalten hervor (Freigabe eines nicht zerstörten Objekts).
- Wie von dir erwähnt keine Methode, um auf Gültigkeit zu prüfen.
get()ist nicht dafür konzipiert. - Kein
swap().