Design von boost::ptr_map



  • Werner Salomon schrieb:

    Wenn ich schon Pointer in Container packe, dann immer als Smart-Pointer (bei Containern dann natürlich shared_ptr).

    shared_ptr ist aber der teuerste Smartpointer (Performance...), so das - sofern nur an einer Stelle die Verwaltung erfolgt, die ptr-Container schon ihren Sinn haben. shared_ptr sind wiederum dann recht gut, wenn man das Objekt an mehreren Stellen hält, und nicht garantieren kann, welche Stelle nun die Speicherverwaltung übernimmt.

    Wobei ich auch lieber einheitlich programmiere, und dann eher zum shared_ptr greife (sofern es sich nicht als Flaschenhals erweist).

    cu André



  • Werner Salomon schrieb:

    Wenn ich schon Pointer in Container packe, dann immer als Smart-Pointer (bei Containern dann natürlich shared_ptr).

    So lange haben wir gekämpft dass smart pointer statt rohen zeiger verwendet werden und dann packen die leute überall nur noch shared_ptr hin anstatt nachzudenken. es ist furchtbar. 😞



  • Man sollte auch dazu sagen, das sich ptr_container und shared_ptr/boost::smart_ptr nicht unbedingt vertragen.

    Weil z.b. man aus einem ptr_container den ptr wieder hinaus bekommt, aber wenn man ihn dann in einen shared_ptr tut, ist der "Rückweg" versperrt, ausser man nutzt clone oder ähnliche Kopiertechniken.



  • phlox81 schrieb:

    Man sollte auch dazu sagen, das sich ptr_container und shared_ptr/boost::smart_ptr nicht unbedingt vertragen.

    Was nie ein Problem darstellt.

    Denn entweder hat die map ownership der Zeiger, dann brauche ich keine shared_ptr oder aber die map hat keinen owner ship, dann brauche ich keine ptr_container sondern nehme normale...



  • Shade Of Mine schrieb:

    So lange haben wir gekämpft dass smart pointer statt rohen zeiger verwendet werden und dann packen die leute überall nur noch shared_ptr hin anstatt nachzudenken. es ist furchtbar. 😞

    Hey, ich habe immerhin die Mühe auf mich genommen, mich in ptr_map einzulesen und mich an die spezielle Schnittstelle zu gewöhnen. 😉

    Ich benutze auch schon länger andere Pointer-Container, zum Beispiel ptr_vector . shared_ptr brauch ich in Containern eigentlich nur, wenn ich Ownership teile oder Elemente von einem in einen anderen Container verschieben will, was bis jetzt allerdings nicht oft vorkam.

    Noch eine Frage: Wenn ich mit BOOST_FOREACH eine ptr_map durchiterieren will, kann ich ja Folgendes tun:

    typedef boost::ptr_map<int, std::string> NumberMap;
    
    NumberMap Map;
    int a = 4;	// jaja...
    int b = 7;
    int c = 0;
    Map.insert(a, new std::string("vier"));
    Map.insert(b, new std::string("sieben"));
    Map.insert(c, new std::string("null"));
    
    BOOST_FOREACH(NumberMap::value_type v, Map)
    {
    	std::cout << v.first << " -> " << *v.second << std::endl;
    }
    

    Warum erhalte ich eine Warnung wegen Referenzen auf temporäre Objekte, wenn ich NumberMap::value_type& schreibe? Bei anderen BOOST_FOREACH -Konstrukten ist doch das auch möglich...



  • Shade Of Mine schrieb:

    Werner Salomon schrieb:

    Wenn ich schon Pointer in Container packe, dann immer als Smart-Pointer (bei Containern dann natürlich shared_ptr).

    So lange haben wir gekämpft dass smart pointer statt rohen zeiger verwendet werden und dann packen die leute überall nur noch shared_ptr hin anstatt nachzudenken. es ist furchtbar. 😞

    Ja - und es hat gar nicht weh getan 😉

    Und trotz shared_ptr haben wir auch das Nachdenken nicht aufgegeben! Es hat sich aber auf ein Abstraktionsstufe höher verlegt - so zwischen zyklischen und wandernden Ownerships mit weak_ptr und enable_from_this. Wie das mit rohen Zeigern hinzubekommen ist ... naja vielleicht weiß volkard das?

    Gruß
    Werner



  • Shade Of Mine schrieb:

    phlox81 schrieb:

    Man sollte auch dazu sagen, das sich ptr_container und shared_ptr/boost::smart_ptr nicht unbedingt vertragen.

    Was nie ein Problem darstellt.

    Denn entweder hat die map ownership der Zeiger, dann brauche ich keine shared_ptr oder aber die map hat keinen owner ship, dann brauche ich keine ptr_container sondern nehme normale...

    Hm, doch doch. Immer dann wenn du unter umständen den Pointer wieder aus der map entfernen willst, ohne ihn zu löschen. Wobei das natürlich dann wiederum so sein kann das man ihn in einen weiteren ptr_container tut.
    Wollte mal für ein undo/redo einen boost::circular_buffer<shared_ptr<T> > machen, das verträgt sich aber nicht, wenn man den aus einem/meheren ptr_containern füttert.



  • Hm... Weiss jemand, wo man bei dem Code

    BOOST_FOREACH(NumberMap::value_type& v, Map) // hier mit Referenz
    { 
        std::cout << v.first << " -> " << *v.second << std::endl; 
    }
    

    eine Non-Const-Referenz an ein temporäres Objekt bindet? Wenn man BOOST_FOREACH sonst einsetzt, funktioniert das doch auch...


  • Administrator

    @Nexus,
    Falls das Problem noch besteht, dann ist hier die Lösung oder die Problembeschreibung:
    Beim Dereferenzieren des Iterators wird ein boost::ptr_container_detail::ref_pair zuückgegeben und zwar ein Objekt und nicht eine Referenz. Dies führt dann natürlich zum Fehler.
    Du kannst aber hier ohne Probleme eine Kopie durchführen. Dieses ref_pair ist intern eine konstante Referenz auf den Schlüssel und der Zeiger auf das Objekt. Dieses ref_pair Objekt ist somit äusserst klein.

    @phlox81,
    Das ist aber weniger das Problem von dem ptr_container , sondern eher das Problem vom shared_ptr . Der shared_ptr hat nämlich keine Möglichkeit den Zeiger freizugeben, also sowas wie ein release durchzuführen. Wieso sowas nicht vorhanden ist, steht hier:
    http://www.boost.org/doc/libs/1_39_0/libs/smart_ptr/shared_ptr.htm#FAQ
    (Zweitletzte Frage/Antwort)

    Grüssli

    PS: Hat einer von euch schon mal angeschaut, was der Präprozessor aus BOOST_FOREACH macht? Komplizierter geht es wohl kaum noch 😃



  • Vielen Dank für die Antwort, Dravere! Das macht natürlich Sinn. Ich hatte es auch mit value_type -Kopien gelöst, es hat mich nur interessiert, weshalb hier eine Warnung entsteht.

    Dravere schrieb:

    PS: Hat einer von euch schon mal angeschaut, was der Präprozessor aus BOOST_FOREACH macht? Komplizierter geht es wohl kaum noch 😃

    Mir hat es eigentlich gereicht, dass bei Drüberfahren mit der Maus ein recht grosser und unübersichtlicher Block mit der Makrodefinition kam. 😉

    Bei Boost schreiben sie:

    BOOST_FOREACH is designed for ease-of-use and efficiency. It [...] makes no calls that are not transparent to the compiler's optimizer. This results in near-optimal code generation; the performance of BOOST_FOREACH is usually within a few percent of the equivalent hand-coded loop.

    1. Beim Profilen mit AMD CodeAnalyst habe ich zumindest noch einige Funktionsaufrufe für BOOST_FOREACH entdecken können (auch wenn diese im Verhältnis zum Programm kaum Zeit benötigen), also ganz wegoptimierbar scheint es mir nicht zu sein. Ich hab allerdings auch nicht allzu lange herumprobiert, einfach mit der Standard-Release-Einstellung bei MSVC++.
    2. Einige wenige Prozent? Das klingt für mich ehrlich gesagt nicht wie nichts. Klar, in vielen Fällen kommt es nicht drauf an, aber bei performancekritischen Anwendungen wäre ich da eher skeptisch. Aber in der Praxis kann es natürlich wieder ganz anders aussehen...


Anmelden zum Antworten