boost::shared_ptr nicht vectorfähig?



  • hi leute

    ich hab folgendes problem
    ich hab einen vector voll boost::shared_pointer auf eine klasse
    ich fülle den vector mit quasi dem nullpendant der klasse
    danach wird der vector bei bedarf mit derivaten dieser klasse überschrieben (d.h. nur halt das element was gebraucht wird wird von base zu derive)

    so nun hab ich halt ein element überschrieben, will bei einem anderen (einem der base elemente) eine methode ausführen, klappt auch
    dann möchte ich aber eine methode von dem derive ausführen und da hakts
    speicherzugriffsverletzungblabla

    ist shared_pointer nicht dafür gebaut mit vererbung umzugehen?!? (kann ich mir nicht vorstellen)
    liegt das daran dass der vector intern was kopiert und sharedptr das nicht mag ?!?

    beim debuggen jedenfalls hängt das genau in der zeile, die position im vector ist richtig (liegt also nichts ausserhalb der vector range), der zeiger von shared ptr ist richtig (da gehts auf jedenfall ohne probleme durch) und dann wenns zur methode gehen sollte krachts

    mfg mosho



  • Es wäre besser, code statt umständlicher Worte zu posten.
    Eigentlich sollte das was du vorhast klappen. Wobei die boost ptr_container wohl eher anzuraten sind.



  • ok, ich versuch das mal zusammenzufassen

    die benutzten klassen

    class Base
    {
    public:
        virtual void init() { /* do what... */ }
        virtual void exit() { /* do what... */ }
    
    protected:
        bool isInit;
    };
    
    class Derive : public Base
    {
        void init()  { /* do what... */ }
        void exit() { /* do what... */ }
    };
    

    main

    int main()
    {
        std::vector<boost::shared_ptr<Base>> vec;
        vec.resize(2);
        for(int i = 0; i < vec.size(); ++i)
            vec[i] = boost::shared_ptr<Base>(new Base);
    
        vec[0]->init();
        // tu was
        vec[0]->exit();
    
        vec[1] = shared_ptr<Base>(new Derive);
        vec[1]->init();   // Hier crashts, 1 ist innerhalb der vector range und der zeiger sollte gültig sein...
    }
    


  • boost::shared_dynamic_cast<> 🙂



  • bei mir "crasht" da nix.



  • Kóyaánasqatsi schrieb:

    boost::shared_dynamic_cast<> 🙂

    Wozu? An seinem gezeigten Code sehe ich jedenfalls kein Grund dafür (Aber ebenso keinen Grund für einen Absturz).



  • std::vector und boost::shared_ptr vertragen sich wunderbar.
    und boost::shared_ptr verträgt sich supi mit Vererbung.

    Dein Problem liegt also vermutlich wo anders. Vielleicht versuchst du ja die Objekte auf die der boost::shared_ptr zeigt einfach nur zugeweisen, wodurch sie "zerschnitten" werden (slicing).

    EDIT: übersehen. Nein, tust du nicht. Keine Ahnung wieso das nicht gehen sollte.

    EDIT2: step doch einfach mal mit dem Debugger rein.



  • Skym0sh0 schrieb:

    class Base
    {
    public:
        virtual void init() { /* do what... */ }
        virtual void exit() { /* do what... */ }
    
    protected:
        bool isInit;
    };
    
    class Derive : public Base
    {
        void init()  { /* do what... */ }
        void exit() { /* do what... */ }
    };
    

    Wenn Du nach einer Übersetzung von "Tu was" suchst, dann würde das "Do something" heißen. 😉

    Ich bemerke, dass Base keinen virtuellen Destruktor hat.

    Skym0sh0 schrieb:

    int main()
    {
        std::vector<boost::shared_ptr<Base>> vec;
        vec.resize(2);
        for(int i = 0; i < vec.size(); ++i)
            vec[i] = boost::shared_ptr<Base>(new Base);
    
        vec[0]->init();
        // tu was
        vec[0]->exit();
    
        vec[1] = shared_ptr<Base>(new Derive);
        vec[1]->init();   // Hier crashts, 1 ist innerhalb der vector range und der zeiger sollte gültig sein...
    }
    

    Zeile 3 des letzten Teils enthält ein ">>" was ein "> >" sein sollte, damit es auch andere Compiler im C++98-Modus fressen. Ohne das Leerzeichen ist das erst gültig ab C++0x, da es sonst als Verschiebe-Operator interpretiert wird.

    Und
    vec[1] = shared_ptr<Base>(new Derive);
    kann man auch kürzer schreiben:
    vec[1].reset(new Derive);

    Obwohl Base keinen virtuellen Destruktor hat, ist dies in diesem Fall ausnahmsweise legal. shared_ptr verwendet template isierte Konstruktoren und reset-Funktionen, so dass der Zeigertyp Derived* erkannt wird. Folgendes funktioniert aber schon nicht mehr richtig (undefined behaviour)
    `

    Base* ptr = new Derive;

    vec[1].reset(ptr);

    `
    da ptr vom Typ Base* ist, Base keinen virtuellen Destruktor hat und daher shared_ptr nicht den richtigen Destruktor aufrufen kann. Also, wenn Du Objekte polymorpher Klassen dynamisch anlegen und löschen willst, sollte der Destruktor der Basisklasse virtuell sein.

    Sonst gibt es nicht viel auszusetzen. Du musst irgendwas anderes falsch gemacht haben; denn das Programm ist kompilierbar und lauffähig.

    kk



  • folgendes hab ich verändert

    int main()
    {
        std::vector<boost::shared_ptr<Base>> vec;
        vec.resize(2);
        for(int i = 0; i < vec.size(); ++i)
            vec[i] = boost::shared_ptr<Base>(new Base);
    
        vec[0]->init();
        // tu was
        vec[0]->exit();
    
        Base * d = new Derive;
        vec[1].reset(d);       // hab reset anstelle dem alten verwendet
        vec[1]->init();   // crasht
    }
    

    achja, und ich hatte die ganze zeit nen virtuellen Dtor
    hab den nur net hier reingeschrieben gehabt...

    klappen tuts nicht
    (( vorm edit dachte ich hätts geklappt, war aber an der falschen stelle ))

    klappt immer noch net...
    mh die speicheraddresse ist 0x00000004
    also eig die zweite int adresse im ram wenn ich das richtig sehe ?!?

    mh ich hab keinen plan warums net geht



  • achja, und ich hatte die ganze zeit nen virtuellen Dtor
    hab den nur net hier reingeschrieben gehabt...

    Wie willst du den Fehler finden, wenn du nie den original Code postest?

    Mal abgesehen davon dass du damit die Zeit anderer Foren-Teilnehmer verschwendest, und das IMO recht unhöflich ist, wirst du auch kaum eine brauchbare Antwort bekommen, wenn du immer irgendwie abgeänderten und/oder unvollständigen Code postest.



  • der original code beläuft sich auf recht viele zeilen, den wollt ihr hier doch auch nicht oder?!?

    ich hab den fehler...

    ich hab in einigen construtoren ZeroMemory
    und das verträgt sich wohl voll nicht mit gewissen sachen

    hab das jetzt rausgemacht und jetzt klappts



  • Skym0sh0 schrieb:

    der original code beläuft sich auf recht viele zeilen, den wollt ihr hier doch auch nicht oder?!?

    Nein, aber man kann erwarten dass der Fragesteller versucht, das Problem so weit einzugrenzen, dass es nicht mehr so viel Code ist. Idealerweise hat er mit dem Debugger &Co einzelne Stellen gefunden, bei denen das Problem auftritt. Dann kann er diesen Bereich posten. Dabei sollte aber der Fehler auftreten, was bei dir nicht der Fall war!

    ich hab in einigen construtoren ZeroMemory

    Und du weißt was ZeroMemory macht?



  • aber ich hab doch den debugger benutzt und auch die ergebnisse geschrieben

    ja zeromemory füllt auf assembler ebene (also recht low level) die gesamte grösse der angegeben struktur mit null(en)

    hab dabei nur nicht bedacht dass manche sachen einfach werte brauchen

    werden dabei eigentlich auch constanten zurückgesetzt?



  • Poste ein kurzes aber vollständiges, kompilierbares Beispiel, welches das Problem enthält. Das erfordert ein Isolieren, Kürzen und Testen Deinerseits. Pseudo-Code runter tippen, von dem Du nur glaubst, dass er den Fehler enthält, führt zu nichts.

    Skym0sh0 schrieb:

    ja zeromemory füllt auf assembler ebene (also recht low level) die gesamte grösse der angegeben struktur mit null(en)

    hab dabei nur nicht bedacht dass manche sachen einfach werte brauchen

    werden dabei eigentlich auch constanten zurückgesetzt?

    Das klingt schon mal sehr nach undefiniertem Verhalten. Aber was Du da genau machst, wissen wir noch nicht, weil Du es nicht gezeigt hast.

    kk


Anmelden zum Antworten