Und was passiert, wenn die unique pointer out of scope gehen und danach der current state oder irgendeine weitere kopie davon nochmal benutzt werden? Wenn der current state kein "Benutzer" ist, dann darfst du die Instanz darueber auch nie benutzen.
Das Verhalten ist auf jeden Fall undefiniert, im Idealfall wird das Programm crashen, der Grund liegt in der falschen Verwendung von
unique_ptr.
Wo fuer dann noch die Kopie, wenn ehh alles im gleichen Scope ist? Meiner Meinung nach ist eben der wirkliche Vorteil eines unique pointers weg, sobald man ihn einmal in einen normalen Pointer kopiert, denn ueber den hat man danach keine Kontrolle mehr. Dann bleibt nur noch ein fancy Weg uebrig, wie du delete aufrufst.
Angenommen jemand kommt jetzt auf die Idee den Play Gamestate nach dem Game Over zu loeschen und wieder neu anzulegen usw.
Es ist ein recht weit verbreitetes Missverständnis, dass Smartpointer irgendwie als Ersatz für rohe Zeiger zu sehen sind, vermutlich kommt das von der sehr unglücklich gewählten Bezeichnung. "Smartpointer" haben rein konzeptionell überhaupt nichts mit Pointern zu tun; Smartpointer und Pointer sind vielmehr völlig orthogonale Konzepte, die einander ergänzen und nicht ersetzen.
Der Schlüssel zum Verständnis von Smartpointern liegt in der Erkenntnis, dass es einen prinzipiellen Unterschied zwischen Besitzern und Benutzern eines Objektes gibt. Besitzer regeln die Lebensdauer, also die Erzeugung und Zerstörung eines Objektes. Unabhängig davon, gibt es Code, der vorhandene Objekte benutzt, um irgendeine Aufgabe zu erfüllen. Dem Benutzer eines Objektes ist es dabei völlig egal, woher die Objekte kommen, wie genau sie erzeugt wurden, oder ob sie dynamische oder automatische oder statische Lebensdauer haben. Ein Besitzer eines Objektes kann auch Benutzer selbiges Objektes sein, nicht jeder Benutzer ist aber unbedingt auch ein Besitzer.
Pointer und Referenzen dienen dazu, eben eine Referenz auf ein existierendes Objekt herumzureichen. Im Falle eines dynamisch erzeugen Objektes, regelt der Code, der sich um das new und delete kümmert, den Besitz am Objekt. Dieser Code wird intern Pointer bzw. Referenzen verwenden, um das zu verwaltende Objekt herumzureichen. Pointer bzw. Referenzen werden ebenfalls verwendet werden, um existierende Objekte an Benutzer weiterzureichen. Wie wir sehen, hat die eigentliche Problematik überhaupt nichts mit Pointern oder Referenzen an sich zu tun.
Die Idee hinter Smartpointern ist, das Konzept des Besitzers eines Objektes zu kapseln. Ein Smartpointer repräsentiert den Besitz an einem Objekt dynamischer Lebensdauer. Das Herumreichen eines Smartpointers entspricht konzeptionell dem Herumreichen des Besitzes am jeweiligen Objekt. Ein
unique_ptr – ein besserer Name wäre wohl beispielsweis einfach nur
owner oder
ownership oder
unique_ownership – repräsentiert den Besitz an einem Objekt, das zu jedem Zeitpunkt nur einen Besitzer haben kann. Ein
unique_ptr kann daher nicht kopiert, sondern nur verschoben werden, was einer Weitergabe des Besitzes am Objekt entsprich. Ein
shared_ptr – ein besserer Name wäre wohl
co_owner oder
shared_ownership – repräsentiert den Besitz an einem Objekt, das mehrere Besitzer haben kann. Ein
shared_ptr kann daher nicht nur verschoben, sondern auch kopiert werden, was der Erzeugung eines neuen Teilhabers am Besitz am Objekt entspricht. In beiden Fällen wird das jeweilige Objekt freigegeben, sobald es keine Besitzer mehr hat. Ironischerweise ist "ein fancy Weg um delete aufzurufen" am Ende also eine sehr treffende Beschreibung exakt dessen, was ein Smartpointer ist. Das "nur" würde ich dabei aber weglassen, denn die Verwaltung der Lebensdauer eines Objektes wird, sobald man es mit einem auch nur ein wenig nichttrivialen Kontrollfluss (man denke dabei insbesondere an Exceptions) zu tun hat, sehr schnell so komplex, dass jeder Versuch einer manuellen Lösung nur in extrem unlesbarem und dabei fast garantiert nicht korrektem Code endet (wer wissen will, wie sowas aussieht, braucht einfach nur mal einen Blick in irgendein Java Projekt zu werfen). Abgesehen davon, sei erwähnt, dass
unique_ptr bei korrekter Verwendung – im Vergleich zur hypothetischen, korrekten, manuellen Lösung –
absolut keinen Overhead erzeugen wird.
Auch wenn wir den Besitz an Objekten mit Smartpointern regeln: Für Pointer bzw. Referenzen auf Objekte verwenden wir Pointer bzw. Referenzen. Was sollte man denn sonst verwenden? Eine Referenz auf einen Smartpointer herumzureichen entspricht konzeptionell dem Herumreichen einer Referenz auf den Besitz an einem Objekt. Code, der eine Referenz auf einen Smartpointer erhält (wir hoffen mal, dass es eine Reference to const ist, sonst kann der jeweilige Code plötzlich sogar noch das Besitzverhältnis Dritter modifizieren), kann theoretisch genauso auf dem vom Smartpointer verwalteten Objekt
delete aufrufen, davor gibt es rein prinzipiell keinen Schutz. Und die Übergabe von Referenzen auf Smartpointer anstatt einfacher Zeiger bzw. Referenzen auf die jeweiligen Objekte ist nicht nur semantisch falsch, sondern auch designmäßig extrem schlecht. Wenn eine Funktion, die ein Objekt einfach nur benutzen soll, plötzlich einen Smartpointer bekommt, funktioniert diese Funktion auf einmal nicht mehr mit allen Objekten des jeweiligen Typs, sondern nur noch mit Objekten, die auf eine bestimmte Weise erzeugt wurden; selbst wenn sich an deinem Smartpointer nur der Deleter ändert (z.B. weil die Objekte von einem custom Allocator kommen), kannst du die Funktion schon nicht mehr benutzen und mit Objekten, die vielleicht einfach nur automatische oder statische Lebensdauer haben, sowieso erst recht nicht...für Code, der ein Objekt nur benutzt, sollte immer nur der Typ des Objektes relevant sein, niemals die Herkunft...
Jo, dann am besten mal ein bisschen informieren, was man damit so macht. Zum Beispiel hier lesen:
http://www.drdobbs.com/cpp/c11-uniqueptr/240002708
Wie bereits gesagt wurde, hatte der Autor dieses Artikels, zum Zeitpunkt als er ihn verfasst hat, offenbar leider tatsächlich
unique_ptr noch nicht so ganz verstanden. Was die Jungs hier beschrieben haben, ist exakt die Art der Verwendung, für die
unique_ptr konzipiert ist. Wenn du ihnen schon nicht glauben magst, vielleicht dann
dem aktuellen Chair des C++ Standardkomitees...