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

TrommlBomml

Community-Fossil

  • »TrommlBomml« ist der Autor dieses Themas

Beiträge: 2 117

Wohnort: Berlin

Beruf: Software-Entwickler

  • Private Nachricht senden

1

29.09.2013, 11:55

c++11 shared_ptr in hierarchischen Datenmodellen

Hi zusammen,

ich habe ein Datenmodell aus klassen, die eine strikte Hierarchie haben sollen. UML-typisch gibt es durch Kompositionen 1-N Beziehungen zwischen Klassen, wobei ich gerne eine Rückreferenz auf dem Vater haben möchte, um bequem navigieren zu können. Der Vater kennt seine Kinder als std::vector<std::shared_ptr<X>>. Die Kinder müssen dann ihre Väter logischerweise über std::weak_ptr<Y> kennen. Wie mache ich dem Kind seinem Vater bekannt? Muss ich einen std::shared_ptr des vaters übergeben? Diesen müsste ich dann ja im Vater selbst haben, also im Vaterobjekt selbst ein std::shared_ptr auf sich selbst haben, was ich etwas schräg finde. Wie würdet ihr das lösen? Ich möchte idealerweise keine Raw-Pointer zumindest in der öffentlichen Schnittstelle haben.

Evrey

Treue Seele

Beiträge: 245

Beruf: Weltherrscher

  • Private Nachricht senden

2

29.09.2013, 13:59

Schau dir mal das an, könnte dich interessieren: http://en.cppreference.com/w/cpp/memory/…hared_from_this
Im Prinzip lässt du deine Parent-Klasse einfach davon erben, und du kannst fortan sorglos immer wieder neue std::shared_ptr davon kreieren. Die konvertierste dann zu std::weak_ptr und übergibst den an die Child-Objekte.

C-/C++-Quelltext

1
2
3
4
int main(int _argc, char** _argv) noexcept {
  asm volatile("lock cmpxchg8b %eax");
  return 0;
} // ::main
(Dieses kleine Biest vermochte einst x86-Prozessoren lahm zu legen.)

=> Und er blogt unter Hackish.Codes D:

patrick246

Treue Seele

Beiträge: 328

Wohnort: nahe Heilbronn/BW

Beruf: TG Profil Informatik-Schüler

  • Private Nachricht senden

3

29.09.2013, 14:13

Gibt es einen Grund für shared_ptr? Ich würde im Vater die Elemente in einem std::vector<std::unique_ptr<X>> speichern und den Kindern dann einen Y* mitgeben. Wenn du dann eine Methode getParent() hast, kannst du diese eine Referenz zurückgeben lassen (return *parent;), der Vater lebt ja eh länger als die Kinder.

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

4

29.09.2013, 17:32

Wenn es tatsächlich eine Komposition und keine Aggregation ist, sehe ich keinen Grund (wie patrick schon sagte) keinen Y* zu nehmen. Smart-Pointer sind nicht dazu gedacht jedwede Art von Pointern zu ersetzen.
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

5

29.09.2013, 17:47

Ich sehe hier auch keinen Grund für shared_ptr, jeder Node hat ja genau einen Besitzer!?

TrommlBomml

Community-Fossil

  • »TrommlBomml« ist der Autor dieses Themas

Beiträge: 2 117

Wohnort: Berlin

Beruf: Software-Entwickler

  • Private Nachricht senden

6

30.09.2013, 07:29

@Evrey: Danke, werde ich mir mal anschauen!

@Rest: Ich habe einen shared_ptr verwendet, weil die Kinder auch nach außen für beliebige andere Datenobjekte erreichbar sein sollen und auch assoziationen zwischen verschiedenen Hierarchieebenen auftreten könne. Und da wollte ich konsequenterweise shared_ptr-instanzen oder bei zylkischen Beziehungen weak_ptr's benutzen. Wenn ich Raw-Pointer benutze, kann ich mir den ganzen smart-Ptr krams doch prinzipiell sparen oder?

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

7

30.09.2013, 08:33

Nein. Smart-Pointer behandeln den automatischen Release basierend auf der Ownership des Objekts hinter dem Pointer. Wenn andere Elemente dieses Objekt referenzieren können, obwohl der Owner tot ist, dann hast Du mehrfache Ownership und eigentlich nicht nur einen Owner. Das ist dann eine Aggregation. Wenn Du eine korrekte Komposition hast, darf es gar nicht auftreten, dass jemand eine Referenz auf das Ding hat, obwohl der Owner/das Parent tot ist. In diesem Fall ist aber ein Smart-Pointer total überflüssig.
Smart-Pointer sind nur eine Ergänzung zu den Pointern, aber waren und sind nicht als kompletter Ersatz von raw-Pointern gedacht und auch gar nicht dafür notwendig. Du kannst natürlich trotzdem shared_ptr und weak_ptr verwenden, dafür sind sie letztlich ja da. Aber dann hast Du ein ganz anderes Verhalten modelliert. Eben keine Komposition, sondern eine Aggregation. Wahlweise auch ein Modell, wo Dein Objekt mehrere Owner haben darf statt nur einen.

Persönlich hätte ich Deine Situation mit dem XML eher als vector<unique_ptr<N>> modelliert und die Children mit einem N* versehen. Ist die Root tot, sind auch die Kinder tot und damit der N* ebenfalls weg. Es kann und darf da eigentlich nicht vorkommen, dass ein N mehrere Owner hat oder auf den Parent zugreift, obwohl das Parent (und damit das Child selbst) ja schon tot ist.
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von »BlueCobold« (30.09.2013, 08:39)


TrommlBomml

Community-Fossil

  • »TrommlBomml« ist der Autor dieses Themas

Beiträge: 2 117

Wohnort: Berlin

Beruf: Software-Entwickler

  • Private Nachricht senden

8

30.09.2013, 08:53

Den Ansatz hatte ich zuerst überlegt. Es ist auch definitiv so, dass der Vater länger lebt als die Kinder. Und genau das definierte Lebensverhalten von Vater zu Kind wollte ich ebend, wie du es beschrieben hast, möglichst sicherstellen. Ausserdem wollte ich den richtigem Umgang mit Smartpointern lernen ;)

Wobei ich trotzdem der Meinung bin, dass ich eine Komposition habe. Der Vater ist der Besitzer, aber andere Datenklassen kennen eine oder vielleicht auch mehrere Klassen, die woanders schon in einer Komposition sind. Meiner Meinung nach reicht es, wenn der Owner die Objekte besitzt und auch wegräumt, andere dürfen sie durchaus kennen und assoziieren, auch über shared_ptr, solang es keine zyklischen Referenzen gibt. Oder worauf möchtest du im Detail hinaus bzgl. Komposition?

Wenn ich also mit uniqe_ptr arbeite, dann definiere ich Assoziationen/Referenzen über Raw-Pointer? Muss ich ja wohl, weil meines Wissen kann ich weak_ptr nur auf Basis von shared_ptr anlegen.

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

9

30.09.2013, 09:36

Wenn das Kind doch aber vor dem Vater stirbt und das Kind die Referenz auf den Vater braucht, wozu sollte es da einen Smart-Pointer benötigen?
Shared_ptr heißt immer, dass die anderen Objekte auch Owner davon sind. Das finde ich in Deinem Fall aber falsch. Owner sollte nur der jeweilige Parent sein.
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

TrommlBomml

Community-Fossil

  • »TrommlBomml« ist der Autor dieses Themas

Beiträge: 2 117

Wohnort: Berlin

Beruf: Software-Entwickler

  • Private Nachricht senden

10

30.09.2013, 09:51

Deswegen hätte ich die Rückreferenz auf dem Vater als weak_ptr gehalten. Wenn der Vater länger lebt, ist die weak-Referenz während der Lebenszeit des Kindes immer gültig. Das war nur eine Frage, ob das so auch sinn macht. Ein Shared_ptr zum Vater keinesfalls. Das "dumme" ist ja bei weak_ptr, dass sie auf Basis eines shared_ptr erzeugt werden. Das kann dann nur der Vater haben - das fand ich einfach nur etwas schräg. Aber Evrey hat genau die Lösung genannt die ich in dem Fall nehmen sollte. Ansonsten wäre natürlich ein Raw-Pointer ebenfalls in Ordnung.

Wobei ich auch ehrlich gesagt nicht daran gedacht habe, dass shared_ptr kein Ownership ist. Ich sehe in shared_ptr einfach eine simple Referenzzählung, bei dem ebend für alle transparent ist, wer das Objekt wegräumen muss. Wenn ein Objekt solange eine shared_ptr-Instanz hält, wäre das auch ok, aber durchaus missbrauch. Frage ist dann aber, was ist der genaue Anwendungsfall für shared_ptr? Bereitstellung eines Objektes ohne konkretes Ownership über verschiedene Objektinstanzen weg?

Werbeanzeige