Pointer/Referenzen kleine Frage



  • Hey Jungs,

    ist nicht genau für solche Fälle der shared_ptr da? Ok, da ist Overhead bei, aber da ist auch garantiert, dass ein Objekt solange lebt bis es nicht mehr gebraucht wird.



  • Skym0sh0 schrieb:

    ist nicht genau für solche Fälle der shared_ptr da? Ok, da ist Overhead bei, aber da ist auch garantiert, dass ein Objekt solange lebt bis es nicht mehr gebraucht wird.

    stimmt, in einem solchen Fall wäre ein shared_ptr sicherlich angebracht. WUrde von cooky ja auch schon erwähnt.



  • Jaja, das hab ich auf dem Schirm. Aber er meinte ja, was von wegen ohne shared_ptr lösen. Die Frage ist wieso?

    Ok, das ganze in die Compiletime zu verlegen wäre schon cool, aber weniger möglich, denke ich.



  • Die Gefahr mit den komischen Speicherbereichen ist gar nicht so riesig.
    Hat es Sinn, das ohne shared_pointers zu machen, dann wird es auch so sein, daß man sich kaum eine mißbräuchliche Verwendung einfallen läßt. Also wenn der string vielleicht sowas wie ein socket provider ist, den man bestimmt nicht löscht, solange sockets von ihm leben könnten. Oder irgendwelche Thread-Multiplexer oder das Welt-Objekt im Game.
    ~~Nicht zu vergessen, daß string vermutlich eh copy-on-write drinnen hat, da haben wie die shard_pointer-Kosten ja schon, vielleicht die ausgabe auch übers Beispiel leiten und Kopie des Strings merken.
    ~~
    Und kurzlebige Proxies natürlich.

    ostream& operator<<(ostream& out,Beispiel const& bsp){
       return out<<time(0)<<' '<<bsp.str;
    }
    ...
    logfile<<Beispiel(msg)<<endl;
    


  • volkard schrieb:

    Nicht zu vergessen, daß string vermutlich eh copy-on-write drinnen hat, da haben wie die shard_pointer-Kosten ja schon, vielleicht die ausgabe auch übers Beispiel leiten und Kopie des Strings merken.

    Ist mit C++11 afaik nicht mehr erlaubt.



  • Kellerautomat schrieb:

    volkard schrieb:

    Nicht zu vergessen, daß string vermutlich eh copy-on-write drinnen hat, da haben wie die shard_pointer-Kosten ja schon, vielleicht die ausgabe auch übers Beispiel leiten und Kopie des Strings merken.

    Ist mit C++11 afaik nicht mehr erlaubt.

    das Forum lernt 🙂
    http://www.c-plusplus.net/forum/p2281175#2281175



  • Skym0sh0 schrieb:

    Jaja, das hab ich auf dem Schirm. Aber er meinte ja, was von wegen ohne shared_ptr lösen. Die Frage ist wieso?

    Hab ich doch auch schon geschrieben. Technisch gesehen ist es sinnloser Overhead. Sprachlich gesehen ist es einfach das falsche Konzept: Es existiert keine shared ownership. Der String hat halt einfach in jedem Fall länger zu leben, wenn das nicht der Fall ist, ist das ein Programmierfehler.



  • cooky451 schrieb:

    Der String hat halt einfach in jedem Fall länger zu leben, wenn das nicht der Fall ist, ist das ein Programmierfehler.

    Und wenn nach einem new kein passendes delete folgt, ist das auch ein Programmierfehler. Das ist aber kein Grund, das Klassendesign nicht so vorzunehmen, dass solche Programmierfehler möglichst ausgeschlossen werden.



  • Lies noch mal den ganzen Thread. 🙄



  • cooky451 schrieb:

    Der String hat halt einfach in jedem Fall länger zu leben, wenn das nicht der Fall ist, ist das ein Programmierfehler.

    Hier wäre eine Mischung von string_reference und initializer_list angebracht:

    template <typename T> granted_lifetime; // Klasse in der Standardbibliothek mit Compilermagie
    Beispiel::Beispiel(granted_lifetime<std::string>);
    
    // ...
    string abc("abc");
    Beispiel bsp1(abc); // abc und bsp sind im automatischen Speicher -> abc konvertiert implizit zu granted_lifetime
    Beispiel *bsp2 = new Beispiel(abc); // bsp liegt liegt im dynamischen Speicher -> Compilerfehler
    
    shared_ptr<string> def = make_shared<string>("abc");
    Beispiel bsp3(def); // shared_ptr konvertiert *immer* zu granted_lifetime
    Beispiel *bsp4 = new Beispiel(abc); // dito
    
    unique_ptr<string> ghi = new string("abc");
    Beispiel bsp5(ghi.get()); // Pointer sind unsicher => Compilerfehler
    Beispiel bsp6(grant_lifetime(ghi.get())); // Garantiere explizit
    


  • cooky451 schrieb:

    Lies noch mal den ganzen Thread. 🙄

    ich habe den Thread verfolgt.

    Wenn man das so programmiert, dann muss der string mindestens so lange Leben, wie das Objekt, das stimmt. Und weil diese Einschränkung leicht umgangen werden kann, sollte überdenken, ob das Design so wirklich sinnvoll ist.



  • @kugelglas Die granted_lifetime Klasse ist nur leider unmöglich zu schreiben denke ich, auch mit Compilermagie.

    Eine Möglichkeit wäre noch eine Klasse zu schreiben in die eben nicht implizit konvertiert wird. Die wäre dann einfach nur Deko und würde gar nichts machen, aber man ist gezwungen von außen kenntlich zu machen, was in der Klasse passiert.

    @daddy_felix Nur weil etwas funktioniert, muss es nicht gut sein. Und wenn du den ganzen Thread gelesen hast, war dein Kommentar sinnlos.



  • cooky451 schrieb:

    @kugelglas Die granted_lifetime Klasse ist nur leider unmöglich zu schreiben denke ich, auch mit Compilermagie.

    Die wichtigsten Spezialfälle könnte man IMHO schon abdecken. Und in die anderen Fällen (welche dann auch für den Code-Leser nicht offensichtlich sind) muss man halt explizit grant_lifetime() aufrufen.

    Und selbst jetzt mit C++11, wenn die Klasse nur Deko wäre, fände ich sie nicht einmal so schlecht. (Die Frage ist nur, wie man sie in die Klasse bekommt, sie darf halt weder Copyable noch Movable sein; wahrscheinlich mit einem weiteren Aufruf von grant_lifetime: s(grant_lifetime(granted)).)



  • Warum sollte sie nicht copy/moveable sein dürfen? Letztlich hofft man da ja auf die Intelligenz des Users und versucht nur Flüchtigkeitsfehler zu vermeiden, da muss man es an der Stelle nicht unnötig kompliziert machen denke ich. Oder übersehe ich da etwas, was leicht schief gehen könnte?



  • granted_lifetime<int> exploit()
    {
      int i;
      granted_lifetime<int> gl(i); // ok, make the constructor explizit for simplicity
      return std::move(gl); // oops
    }
    


  • Ja, aber genau das meine ich nicht mit "kann leicht schief gehen". Es gibt genau eine Stelle, an der granted_lifetime stehen kann: Als Parameter. Und es gibt genau eine Stelle, an der grant_lifetime stehen kann: Wenn man den Parameter übergibt. Wenn etwas innerhalb dieses Konzepts schief gehen kann, dann lohnt es sich vielleicht das zu verhindern. Aber beim Rest erscheint mir das, wie schon geschrieben, in Anbetracht der Tatsache dass die Klasse sowieso keine richtigen Garantien liefern kann und quasi nur Deko ist, einfach nicht sinnvoll.



  • cooky451 schrieb:

    Es gibt genau eine Stelle, an der granted_lifetime stehen kann: Als Parameter.

    So einfach ist das nicht. Damit das auch wirklich funktioniert, muss granted_lifetime ein shared_ptr halten, wenn man einen shared_ptr übergibt und nur einen Pointer, wenn man eine Referenz übergibt. Also muss granted_lifetime, so wie ich sie vorgestellt habe, starken Gebrauch von Type-Erasure machen (wie std::function).

    Die Alternative wäre, die gesamte Klasse Beispiel zu einem Template abzuändern.

    Irgendwie ist dann std::shared_ptr doch einfacher und performanter.



  • Ja, das würde so alles überhaupt keinen Sinn machen. Das Konzept ist von shared_ptr völlig unabhängig, insofern: Doch, es ist so einfach. 😉



  • cooky451 schrieb:

    Das Konzept ist von shared_ptr völlig unabhängig

    Das geht aber nicht. Wie will dieser Code funktionieren, wenn Beispiel keinen shared_ptr hält?

    shared_ptr<string> def = make_shared<string>("abc");
    Beispiel bsp3(def); // shared_ptr konvertiert *immer* zu granted_lifetime
    def.reset();
    


  • Gar nicht? shared_ptr ist einfach ein völlig anderes Konzept. Die beiden zu koppeln bringt nichts. Entweder man will einen shared_ptr, oder eben eine garantierte Lebenszeit.


Anmelden zum Antworten