Von shared_ptr nach ptr_vector



  • Gute Tag,

    ich überlege gerade mein vorgehen bezüglich des überführens eines shared_ptr in einen ptr_vector, beide aus boost.

    Ein minimalbeispiel:

    class Foo
    {
       public: 
       [...]
    
       private:
       boost::ptr_vector<MyObject> MyObjectVector;
    };
    
    void Foo::addElement(boost::shared_ptr my_shared_ptr)
    {
       MyObjectVector.push_back(my_shared_ptr.get());
    }
    

    Ist es richtig, dass ich den Raw-Pointer aus dem shared_ptr per get() holen, und ihn dann per push_back in den ptr_vector überführen muss?

    Danke!

    Grüße, Alfred



  • Dürfte so nicht funktionieren, da der ptr_vector den Besitz über den Zeiger übernimmt. Damit haben sowohl der shared_ptr als auch ptr_vector Besitz und erzeugen beim Zerstören UB.
    Du willst den Besitz vom shared_ptr auf den ptr_vector übertragen, ich weiß allerdings nicht, ob und wie sowas geht.



  • Nein, das geht so nicht. der shared_ptr besitzt das Objekt immer noch und würde es zerstören, sobald alle shared_ptr instanzen zerstört wurden. Die beiden Dinge modelleiren unterschiedliche Konzepte: ptr_vector besitzt das Objekt und wenn er stirbt, löscht er alle Objekte. Der shared_ptr hingegen wird verwendet, wenn niemand alleine das Objekt besitzt. Deswegen macht es keinen Sinn, einen shared_ptr an einen ptr_vector zu übertragen.

    Was du machen kannst:

    void Foo::addElement(boost::shared_ptr& my_shared_ptr)//non-const referenz!
    {
       if(!my_shared_ptr.unique()){//es gibt mehrere Instanzen von dem Teil, da ist nichts mehr zu machen.
           throw IrgendeineException();
       }
       MyObjectVector.push_back(my_shared_ptr.get());
       my_shared_ptr.release();
    }
    

    Nur in dem Fall, das der shared_ptr nicht shared ist, kannst du übertragen. Also keine gute Lösung.



  • Was du willst ist unique_ptr und nicht shared_ptr. Und wenn du den hast, kannst du einfach gleich einen std::vector<std::unique_ptr<MyObject>> verwenden 😉



  • DocShoe schrieb:

    Du willst den Besitz vom shared_ptr auf den ptr_vector übertragen, ich weiß allerdings nicht, ob und wie sowas geht.

    Das geht nicht. Ein shared_ptr lässt sich nicht mehr "entbinden". Bei einem auto_ptr ginge das mit release() .

    Eine Erkärung, warum es nicht geht, findest du hier: http://stackoverflow.com/questions/1525764/how-to-release-pointer-from-boostshared-ptr



  • Vielen dank für die antworten. Angeregt durch eure antworten bin ich auch zu dem schluss gekommen, dass es blödsinn ist, was ich vorhabe, da die o.g. besitzverhältnisse existieren, bzw. eben die objekte gelöscht werden.

    Ich werde mein konstrukt auf einen std::vector mit shared_ptr umbauen.



  • dot schrieb:

    Was du willst ist unique_ptr und nicht shared_ptr. Und wenn du den hast, kannst du einfach gleich einen std::vector<std::unique_ptr<MyObject>> verwenden 😉

    Darf man die überhaupt in einen vector stecken? Immerhin sind die non-copyable und non-assignable. D.h. ein simples push_back() kann alles kaputt machen.



  • otze schrieb:

    Darf man die überhaupt in einen vector stecken? Immerhin sind die non-copyable und non-assignable. D.h. ein simples push_back() kann alles kaputt machen.

    Äh.. nein. Denk da noch mal drüber nach. Das funktioniert problemlos. 😉



  • otze schrieb:

    Darf man die überhaupt in einen vector stecken?

    natürlich, unique_ptr ist auto_ptr richtig gemacht... 😉

    otze schrieb:

    Immerhin sind die non-copyable und non-assignable.

    Aber sie sind moveable. 😉

    otze schrieb:

    D.h. ein simples push_back() kann alles kaputt machen.

    Nope, funktioniert problemlos.



  • dot schrieb:

    otze schrieb:

    Immerhin sind die non-copyable und non-assignable.

    Aber sie sind moveable. 😉

    Ahh C++11 mal wieder. Ich hatte noch std::tr1::unique_ptr aus C++03 im Kopf 😉



  • Alf1979 schrieb:

    Vielen dank für die antworten. Angeregt durch eure antworten bin ich auch zu dem schluss gekommen, dass es blödsinn ist, was ich vorhabe, da die o.g. besitzverhältnisse existieren, bzw. eben die objekte gelöscht werden.

    Ich werde mein konstrukt auf einen std::vector mit shared_ptr umbauen.

    Was für Besitzverhältnisse existieren denn in deiner Anwendung da genau? Wieso müssen mehrere Objekte den Besitz dieser Dinge, die du da in den vector packen willst, teilen?



  • Naja, teilen ... es ist einfach eine vorgabe der entwicklungsleitung meiner firma, da hat es geheißen: "verwendet smart pointer".

    Und da ich bei boost die wahl zwischen scoped_ptr und shared_ptr habe, habe ich mich für shared_ptr entschieden.

    Wenn ich mich nicht irre, wäre unique_ptr die bessere wahl, aber der c++11 standard wird bei uns erst in ca. 1 bis 1,5 jahren einzug erhalten.



  • Oh, das ist schade, shared_ptr ist eigentlich in der Regel keine gute Wahl, denn shared Ownerschip braucht man am besten nie und shared_ptr ist ein ziemliches Schwergewicht...
    Ich würde an deiner Stelle eher versuchen, std::auto_ptr zu verwenden. Dann eben zusammen mit boost::ptr_vector.



  • Ja, wenn du nur etwas brauchst um kurzfristig ein gerade erzeugtes Objekt zu speichern, dann ist auto_ptr deine beste Wahl. Dann ist auch klar, dass damit der Besitz transferiert wird.



  • otze schrieb:

    Ich hatte noch std::tr1::unique_ptr aus C++03 im Kopf 😉

    Das gibt's doch gar nicht. Und TR1 ist auch nicht in C++03 drin.



  • Welche Gründe gibt es für euch nach für die Verwendung von boost::ptr_vector<T>?

    Also generell fand ich es immer schön, dass man bei Iterieren gleich eine Referenz hatte und keinen Pointer, aber das ist ja eigentlich kein Grund diese zusätzliche Library im Programm zu verwenden.
    Zudem konnte man bestimmen, wie die Elemente in dem vector geclont werden sollen...
    Naja... Aber auch das ist auch irgendwie nicht das richtig überzeugende Argument für mich. So oft brauch man es auch nicht und so ne kleine Funktion ist schnell geschrieben.

    Sterben die Pointer-Container bald aus oder welche Argumente habt ihr für die Verwendung der Pointer-Container?

    Gruß,
    XSpille



  • Obwohl ich den vector<unique_ptr<T>> weniger schön als ptr_vector finde, verzichte ich aufgrund der Abhängigkeit zu Boost darauf.

    Dabei hat ein ptr_vector so viele Vorteile:

    • Schönere Syntax, bzw. einheitliche Syntax zu einem pointerlosen Container
    • Kopierbar
    • Sortierbar (sort auf vector<unique_ptr<T>> vergleicht deren Speicherposition)
    • Allgemein für STL Algorithmen geeignet, bei vector<unique_ptr<T>> muss man boost::indirect_iterator verwenden und dann hat man wieder eine (wenn auch minimale) Boost-Abhängigkeit


  • Danke für die vielen antworte.

    Was mir aufgefallen ist, etwas weiter oben habe ich den hinweis bekommen, auto_ptr zu verwenden: boost::ptr_vector<std::auto_ptr<T>>

    Aber das kann doch gar nicht funktionieren, oder? Da auto_ptr nicht zusammen mit std::vector verwendet werden kann, und boost::ptr_vector baut doch auch auf std::vector auf?



  • Alf1979 schrieb:

    Aber das kann doch gar nicht funktionieren, oder? Da auto_ptr nicht zusammen mit std::vector verwendet werden kann, und boost::ptr_vector baut doch auch auf std::vector auf?

    Du darfst keinen std::vector<std::auto_ptr<T> > machen, genau darum gibt es boost::ptr_vector ja überhaupt erst. Du sollst auch keinen boost::ptr_vector<std::auto_ptr<T> > machen, sondern du willst sowohl boost::ptr_vector als auch std::auto_ptr verwenden. auto_ptr zum Rumreichen von Objekten an den neuen Besitzer, ptr_vector zum Halten deiner mit new erzeugen Instazen. Wobei ich mir an deiner Stelle sowieso erst mal überlegen würde, ob der Besitzwechsel überhaupt notwendig und sinnvoll ist, oder ob ich nicht ein besseres Design finden kann, wo die Objekte auch dort zerstört werden, wo sie erzeugt wurden und eigentlich maximal ein ptr_vector oder so ausreicht...

    lanzenwerfer schrieb:

    Dabei hat ein ptr_vector so viele Vorteile:

    • Schönere Syntax, bzw. einheitliche Syntax zu einem pointerlosen Container
    • Kopierbar
    • Sortierbar (sort auf vector<unique_ptr<T>> vergleicht deren Speicherposition)
    • Allgemein für STL Algorithmen geeignet, bei vector<unique_ptr<T>> muss man boost::indirect_iterator verwenden und dann hat man wieder eine (wenn auch minimale) Boost-Abhängigkeit

    Lambdas machens besser ;). Abgesehen davon, find ich Move Semantik hier viel sauberer und bevorzuge std::vector<std::unique_ptr<T>> schon allein wegen der Konsistenz mit dem Rest der STL...



  • Alf1979 schrieb:

    Was mir aufgefallen ist, etwas weiter oben habe ich den hinweis bekommen, auto_ptr zu verwenden: boost::ptr_vector<std::auto_ptr<T>>

    Aber das kann doch gar nicht funktionieren, oder? Da auto_ptr nicht zusammen mit std::vector verwendet werden kann, und boost::ptr_vector baut doch auch auf std::vector auf?

    Das hast du falsch verstanden. Es war so gemeint:

    auto_ptr<int> quelle();
    
    int main()
    {
      ptr_vector<int> v;     // <-- nix mit auto_ptr
      v.push_back(quelle()); // <-- ptr_vector befreit und übernimmt den rohen
                             //     Zeiger aus dem auto_ptr (ownership transfer)
    }
    

Anmelden zum Antworten