Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

TGGC

1x Rätselkönig

Beiträge: 1 799

Beruf: Software Entwickler

  • Private Nachricht senden

11

15.09.2015, 11:09

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.

12

15.09.2015, 11:46

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.

Dann knallt es! Aber das Design muss halt so gewählt werden (wie hier es ja ist) das der unique-Besitzer im selben Scope wie der RAW-Pointer ist oder in der Hierarchie drüber.
Wir nutzen das in RR auch so und es funktioniert wunderbar.
Wer aufhört besser werden zu wollen hört auf gut zu sein!

aktuelles Projekt:Rickety Racquet

TGGC

1x Rätselkönig

Beiträge: 1 799

Beruf: Software Entwickler

  • Private Nachricht senden

13

15.09.2015, 12:40

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.

TrommlBomml

Community-Fossil

Beiträge: 2 117

Wohnort: Berlin

Beruf: Software-Entwickler

  • Private Nachricht senden

14

15.09.2015, 14:45

C++ ist nun ja nicht gerade die Sprache, mit der man sich gegen deine Anwendungsfälle absichern kann. Mir fällt kein Weg ein, wo einer sich "dumm" anstellen kann ohne was kaputt zu machen. Mit entsprechender Architektur und der richtlinie, dass raw-Pointer nicht gelöscht werden dürfen (statische codeanalyse könnte das automatisch absichern), kann man das fehlerpotenziel bei pointern stark reduzieren. Und ich würde jetzt mal frech behaupten, wenn ein durch ein unique_ptr "raw" rausgereichter pointer nicht mehr gültig ist, dann ist wohl vermutlich der Besitzer nicht der richtige.

Hello_Kitty!

unregistriert

15

15.09.2015, 15:23

Und was passiert, wenn die unique pointer out of scope gehen und danach der current state oder irgendeine weitere kopie davon nochmal benutzt werden?
Dann ist das ein Bug und den zu beheben ist die Aufgabe des Programmierers, der Code muss ja nicht robuster als das Produkt selbst sein. Mit diesem ständigen Misstrauen vor sich selbst kann man vielleicht bestimmte Fehlerklassen manchmal vermeiden, aber dem stehen auch immer andere Kosten gegenüber. Und was ist jetzt, wenn ein Programmierer nach dir deine paranoide Lösung nicht kapiert und trotzdem einen Rawpointer verwendet? Der Punkt ist, dass du ohne ausreichendes Verständnis über das System sowieso nicht produktiv daran arbeiten kannst.

16

15.09.2015, 16:06

Wo fuer dann noch die Kopie, wenn ehh alles im gleichen Scope ist?

Um z.B. nicht durch einen Container zu iterieren um den Richtigen State rauszusuchen oder um vom Ressourcenmanager (Der dann wohl nicht mehr im selben Scope ist) ein Raw-Pointer auf die Resource zu holen.

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.

Wenn ich ihn wirklich unique anwenden dann kann ich mir auch den Overhead eines std::unique_ptr sparen und programmier von Haus mit Raw-Pointern und erstelle ihn sauber im Konstrukter und lösche ihn sauber im Destruktor.
Weiterhin hätten sich die Programmier die get-Methode gespart, wenn das ihr ansinnen gewesen wäre SmartPointer "wirklich" unique zu machen.

Ich glaube das genau für solche Anwendungsfälle der std::unique_ptr geeignet ist.
- Es gibt einen Besitzer
- dieser wird als erstes erzeug
- dieser wird als letztes gelöscht
- und wieviel unkontrollierte raw-Pointer dann dazwischen erzeugt werden spielt gar keine Rolle

Wenn das nicht der Fall ist, dann ist std::unique_ptr das falsche mittel!
Wer aufhört besser werden zu wollen hört auf gut zu sein!

aktuelles Projekt:Rickety Racquet

TrommlBomml

Community-Fossil

Beiträge: 2 117

Wohnort: Berlin

Beruf: Software-Entwickler

  • Private Nachricht senden

17

16.09.2015, 15:24

Da es gerade zu dem Thema passt. Wenn John Carmack das schon sagt... (Twitter)

Zitat von »"John Carmack"«

‏@ID_AA_Carmack 8. Sep.
Happy that we finally allow C++11 in the Oculus mobile codebases -- tons of places where unique_ptr is a big help.

TGGC

1x Rätselkönig

Beiträge: 1 799

Beruf: Software Entwickler

  • Private Nachricht senden

18

16.09.2015, 15:29

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

Beiträge: 1 223

Wohnort: Deutschland Bayern

Beruf: Schüler

  • Private Nachricht senden

19

16.09.2015, 20:47

Wenn du auf den Maschinencode Vergleich dort hinaus willst: Der ist schwachsinnig
Der Vergleich ist unfair, weil der unique_ptr durch eine Referenz eine zusätzliche Indirektion hat:

C-/C++-Quelltext

1
2
int inc_bazp(foo *p) { ... }
int inc_baz(std::unique_ptr<foo>& p) { ... }

Das wäre ein fairer Vergleich:

C-/C++-Quelltext

1
2
int inc_bazp(foo *p) { ... }
int inc_baz(std::unique_ptr<foo> p) { ... }


Der Autor hatte vermutlich den Sinn von unique_ptr noch nicht ganz verstanden. Der einzige Grund warum man einen unique_ptr als Referenz übergeben sollte ist der selbe wie mit einem normalen Pointer als Referenz. Nur wenn man den Pointer im Parameter ändern möchte (als "Ausgabeparameter"), ist es sinnvoll ihn als Referenz zu deklarieren. Hier wird im Prinzip das falsche Besitzverhältnis ausgehebelt. Ein direkter unique_ptr würde nicht funktionieren, weil dann der Methode der Besitz von "foo" übergeben würde und das Objekt anschließend zerstört würde. Deshalb meint er, er müsse eine Referenz auf den Besitzer übergeben.

Der Autor hat also scheinbar noch nicht bemerkt, dass unique_ptr Raw Pointer nicht ersetzen und an der Stelle der Funktion ein unique_ptr einfach völlig fehl am Platz ist, weil er in dem Fall Besitz nicht an die Methode übergeben möchte. Natürlich kann der eigentliche Besitzer "foo" als unique_ptr halten, allerdings sollte man der Methode das Objekt als Raw-Pointer (get()-Methode) oder Referenz übergeben. An der Stelle hätte der smarte Pointer daher eigentlich nur Nachteile. Man kann zum Beispiel auch keine Objekte übergeben, die auf dem Stack liegen.

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

20

20.09.2015, 23:25

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... ;)

Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von »dot« (21.09.2015, 00:22)


Werbeanzeige