Speicher freigeben, durch aufeinanderfolgende Zeiger



  • Nimm einfach shared_ptr. Ist zwar hier ziemlich verhasst aber das Ding macht in den meisten Fällen das Richtige.



  • hustbaer schrieb:

    Nö. Eher an single ownership vs. shared ownership.
    http://stackoverflow.com/questions/13852710/single-vs-shared-ownership-meaning

    Danke, seh ich mir an.

    hustbaer schrieb:

    Wenn du etwas genauer beschreibst was ein Element eines Objektes ständig "mitverfolgen" bedeutet könnte dir vielleicht jmd. nen konkreteren Tip geben.

    Im Grunde genommen, will ich das ein Objekt ein anderes verfolgt(also im dreidimemsionalen Raum). Beide Objekte sind auch im Code zwei verschiedene Objekte.
    Also dachte ich, ich könnte einfach die Addresse des zu verfolgenden Objektes in einen Zeiger laden, um so dann ständig die Position auszulesen.

    hustbaer schrieb:

    Dazu kann man sich was basteln, wenn man es denn wirklich braucht.
    Wenns nicht threadsafe sein muss sollte ein shared_ptr<shared_ptr<Foo>> reichen.

    Ethon schrieb:

    Nimm einfach shared_ptr. Ist zwar hier ziemlich verhasst aber das Ding macht in den meisten Fällen das Richtige.

    Okay, danke.



  • coder++ schrieb:

    Ich benutze auch die Container-Klassen.
    Aber ich muss ein Element eines Objektes ständig "mitverfolgen".
    Da fiel mir als erstes ein Zeiger auf das Objekt ein.
    Ich schau mal, ob ich einen besseren Weg finde.
    Danke.

    Das hört sich für mich nach Observer-Pattern an.



  • coder++ schrieb:

    hustbaer schrieb:

    Wenn du etwas genauer beschreibst was ein Element eines Objektes ständig "mitverfolgen" bedeutet könnte dir vielleicht jmd. nen konkreteren Tip geben.

    Im Grunde genommen, will ich das ein Objekt ein anderes verfolgt(also im dreidimemsionalen Raum). Beide Objekte sind auch im Code zwei verschiedene Objekte.
    Also dachte ich, ich könnte einfach die Addresse des zu verfolgenden Objektes in einen Zeiger laden, um so dann ständig die Position auszulesen.

    Observer-Pattern wurde ja schon genannt.
    Zwei Observer-Pattern Varianten:

    1. Die Position des Objekts ist "observable" - d.h. das Objekt benachrichtigt andere über Positionsänderungen.
    2. Die Lebenszeit des Objekts ist "observable" - d.h. das Objekt benachrichtigt andere wenn es zerstört wird.
      1 und 2 kann man natürlich auch kombinieren.

    Ansonsten bietet sich shared_ptr an.

    Wenn du willst dass der Verfolger das Ziel (den Verfolgten) am Leben hält, dann bekommt der Verfolger nen shared_ptr<Ziel> , und fertig.
    Das Ziel wird dann durch den Verfolger am Leben gehalten - es wird ja erst gelöscht wenn es keine shared_ptr mehr darauf gibt.

    Bzw. wenn du die Lebenszeit des Ziels unabhängig vom Verfolger kontrollieren willst, dann kannst du dem Verfolger auch einfach einen weak_ptr<Ziel> geben.

    Oder, wenn die Partei die die Lebenszeit des Ziels kontrolliert einen Level "überhalb" des Verfolgers angesiedelt ist, und das Verfolger Objekt auch "kennt", dann kannst du im Prinzip auch rohe Zeiger verwenden. Die Lebenszeit-kontrollierende Partei muss dann einfach nur verfolger->SetzeZiel(NULL) aufrufen bevor das Ziel gelöscht wird.
    Wobei das die am wenigsten "sichere" Variante ist. Weil Fehler die du dabei evtl. machst u.U. nicht oder erst spät auffallen.

    Wenn es sonst keine Punkte gibt die dagegensprechen (oder für eine andere Lösung) würde ich hier shared_ptr verwenden. Entweder, wenn das erwünscht ist, shared Ownership mit mehreren shared_ptr . Oder halt shared_ptr beim Owner und weak_ptr beim Verfolger.



  • Ich hab mir jetzt deinen Link zu single und shared ownership angesehen.

    Also wenn ich das richtig verstanden habe, wird bei einem unique_ptr der Speicher freigegeben, sobald er zerstört wird.
    Bei einem shared_ptr erst, wenn ALLE Referenzen zerstört werden.

    Also könnte ich doch mit mehreren Instanzen den gleichen Speicherbereich addressieren, sodass dieser erst freigegeben wird, sobald alle Instanzen zerstört werden, oder?

    Haltet ihr es generell sinvoll einen unique_ptr zu verwenden, anstatt eines standardmäßigen Zeigers? So muss man nicht daran denken, den Speicher selbst freizugeben und beugt so Speicherlücken(kann man so verlorenen Speicher bezeichnen?) vor.
    Einfacher ist es natürlich, Zeiger möglichst wenig zu verwenden und wenn dann vorsichtig mit ihnen umgehen, aber es steigert ja außerdem die Lesbarkeit und verhindert "Speichermüll".



  • coder++ schrieb:

    Haltet ihr es generell sinvoll einen unique_ptr zu verwenden, anstatt eines standardmäßigen Zeigers? So muss man nicht daran denken, den Speicher selbst freizugeben und beugt so Speicherlücken(kann man so verlorenen Speicher bezeichnen?) vor.

    In modernem C++ sind "besitzende" rohe Zeiger verpönt. Es ist also keine schlechte Idee unique_ptr zu verwenden.



  • MichelRT schrieb:

    coder++ schrieb:

    Haltet ihr es generell sinvoll einen unique_ptr zu verwenden, anstatt eines standardmäßigen Zeigers? So muss man nicht daran denken, den Speicher selbst freizugeben und beugt so Speicherlücken(kann man so verlorenen Speicher bezeichnen?) vor.

    In modernem C++ sind "besitzende" rohe Zeiger verpönt. Es ist also keine schlechte Idee unique_ptr zu verwenden.

    Okay, danke.
    Irgendwie hab ich das nie wirklich mitgekriegt, dass rohe Zeiger nicht mehr in modernes C++ gehören.



  • coder++ schrieb:

    Okay, danke.
    Irgendwie hab ich das nie wirklich mitgekriegt, dass rohe Zeiger nicht mehr in modernes C++ gehören.

    Doch schon, aber sie sollen eben nur zeigen und nichts anderes.
    Wenn man einen Besitz und damit die Pflicht zur Speicherfreigabe ausdruecken will, verwendet man soweit moeglich unique_ptr. Wenn es mehr als einen Besitzer gibt, sollte man erstmal sein Design ueberdenken und dann ggf. shared_ptr verwenden. shared_ptr schuetzt auch nicht in allen Situationen, z.B. bei zyklischen Abhaengigkeiten geht das nicht, die sollte man aber so gut wie nie haben.
    Nebenbei gilt noch, dass man fuer pointer auf Arrays ( int ptr = new int[10];* ) kein unique_ptr, sondern Container nehmen sollte.



  • Marthog schrieb:

    coder++ schrieb:

    Okay, danke.
    Irgendwie hab ich das nie wirklich mitgekriegt, dass rohe Zeiger nicht mehr in modernes C++ gehören.

    Doch schon, aber sie sollen eben nur zeigen und nichts anderes.
    Wenn man einen Besitz und damit die Pflicht zur Speicherfreigabe ausdruecken will, verwendet man soweit moeglich unique_ptr. Wenn es mehr als einen Besitzer gibt, sollte man erstmal sein Design ueberdenken und dann ggf. shared_ptr verwenden. shared_ptr schuetzt auch nicht in allen Situationen, z.B. bei zyklischen Abhaengigkeiten geht das nicht, die sollte man aber so gut wie nie haben.
    Nebenbei gilt noch, dass man fuer pointer auf Arrays ( int ptr = new int[10];* ) kein unique_ptr, sondern Container nehmen sollte.

    Achso. Ich dachte mit rohen Zeigern sind schon nur die Zeiger gemeint, welche Speicher angefordert haben.
    Und für Arrays benutze ich meistens sowieso vector und je nach dem auch map aus der Standardbibliothek.



  • coder++ schrieb:

    Irgendwie hab ich das nie wirklich mitgekriegt, dass rohe Zeiger nicht mehr in modernes C++ gehören.

    Das entscheidende ist der Zusatz "besizende" rohe Zeiger.
    Als Parameter für Funktionen/Methoden sind Zeiger natürlich nach wie vor erlaubt.
    Tabu ist natürlich das Speicher(also in Besitz nehmen) des so übergebenen Zeigers über die Lebenszeit der Funktion/Methode.



  • Ich wollte mal fragen, ob folgendes Minimal-Beispiel funktioniert, bzw. ob der Speicher erst nach löschen der Addressen aus beiden shared_ptren freigegeben wird.

    boost::shared_ptr<int> sp1(new int);
    
    boost::shared_ptr<int> sp2;
    sp2.reset(sp1.get()); // Es wird die Addresse, nicht der shared_ptr übergeben
    
    sp1.reset();
    std::cout << *sp2; /* "Weiß" sp1, dass sp2 existiert und hat den Speicher nicht freigegeben, oder eben nicht, wodurch der Speicher freigegeben und vielleicht schon neu belegt wurde? */
    sp2.reset();
    

    In diesem Beispiel geht es mir darum, ob ich den shared_ptr kopieren muss, oder ob es schon reicht die gleiche Addresse zu laden, da get() ja die wirkliche Addresse zurückgibt.



  • Das löscht zwei mal.



  • manni66 schrieb:

    Das löscht zwei mal.

    Der Speicher wird beides mal freigegeben?
    Was hab ich falsch gemacht?



  • Du musst

    boost::shared_ptr<int> sp2;
    sp2.reset(sp1.get()); // Es wird die Addresse, nicht der shared_ptr übergeben
    

    durch

    boost::shared_ptr<int> sp2 = sp1;
    

    ersetzen. Andernfalls zeigen beide shared_ptr auf den gleichen Wert, wissen aber nicht von dem anderen und meinen dass sie die einzigen sind. Beide versuchen beim Ableben den Wert freizugeben, beim zweiten kracht es.

    Wenn du die die Zeiger direkt kopierst dann zeigen beide auf den gleichen Wert, wissen indirekt von dem anderen Zeiger und nur der letzte gibt frei.



  • Ethon schrieb:

    Du musst

    boost::shared_ptr<int> sp2;
    sp2.reset(sp1.get()); // Es wird die Addresse, nicht der shared_ptr übergeben
    

    durch

    boost::shared_ptr<int> sp2 = sp1;
    

    ersetzen. Andernfalls zeigen beide shared_ptr auf den gleichen Wert, wissen aber nicht von dem anderen und meinen dass sie die einzigen sind. Beide versuchen beim Ableben den Wert freizugeben, beim zweiten kracht es.

    Wenn du die die Zeiger direkt kopierst dann zeigen beide auf den gleichen Wert, wissen indirekt von dem anderen Zeiger und nur der letzte gibt frei.

    Danke.

    Also ist reset() ja eigentlich nur dafür da, neuen Speicher anzufordern.



  • Jap. Zb so:

    shared_ptr<int> sp(new int);
    sp.reset(new int);
    // Kein Leak
    


  • Ethon schrieb:

    Jap. Zb so:

    shared_ptr<int> sp(new int);
    sp.reset(new int);
    // Kein Leak
    

    Okay.


Anmelden zum Antworten