boost::shared_ptr in multimap einbauen - doppelter key will nicht.



  • hallo,

    aaalso ich habe eine std::multimap byId vom Typ

    typedef multimap<Token::ptr, Thesis::ptr> idmap;

    die ::ptr sind shared_ptr auf die entsprechende Klasse.

    diese bekommt daten aus einer Textdatei eingepflegt. Der Textdateiparser funktioniert so weit ganz gut, ich erhalte eine Instanz von Thesis, welche meine Daten beinhaltet, unter Anderem ein subject mit dem Typ Token::ptr.

    Fülle ich jetzt Daten mittels

    this->byId.insert(pair<Token::ptr, Thesis::ptr> (t->subject, t));

    in meine multimap, funktioniert dieses nur, solange die key's nicht den gleichen Wert beinhalten- das ist allerdings ungünstig, weil macht ja die multimap erst aus..

    Wo hab ich jetzt das Problem?
    die generierten Daten sind jedes Mal neue Instanzen- auch, wenn die Werte gleich sind. Könnte er sich daran stoßen?

    Edit: Der Laufzeitfehler gestaltet sich wie folgt:
    /usr/include/boost/shared_ptr.hpp:315: T* boost::shared_ptr<T>::operator->() const [with T = semnet::Word]: Assertion `px != 0' failed.



  • Kannst du die genaue Stelle ausfindig machen, an dem der Fehler auftritt?

    Das klingt für mich in meinem jugendlichen Leichtsinn danach, dass du zuerst einen shared_ptr (implizit) default-konstruierst und ihn später (implizit) dereferenzierst.



  • joa, das scheints gewesen zu sein. hab in meiner klasse zwei alternierende elemente, die jetzt jeweils einen defaultwert kriegen- schon klappts..

    was allerdings jetzt noch immer nicht geht, ist das Auffinden von Elementen mittels equal_range:

    Database::tokeniterator tit = database->findbyToken(Token::ptr(new Token("#1")));
            Database::idmap::iterator it2;
            for (it2 = tit.first; it2 != tit.second; ++it2) {
                cout << (*it2).second->toString() << endl;
            }
    

    dies gibt bei mir nichts aus und das, obwohl eindeutig ein Token namens #1 existiert.

    Token sieht so aus:

    class Token : public DBElement {
            private:
                uint32_t id;
                static uint32_t maxid;
    
                void setId (uint32_t id);
    
                virtual void fromString(string s);
    
            public:
                typedef boost::shared_ptr<Token> ptr;
    
                virtual string toString();
                virtual const uint32_t getId();
    
                Token();
                Token(uint32_t pid);
                Token(string pToken);
                Token(ptr p);
    
                bool operator== (Token & pToken);
                bool operator== (const uint32_t pId);
                bool operator<  (Token & pToken);
                bool operator<  (const uint32_t pId);
    
                static bool isToken (string pString);
        };
    

    mit folgender Implementierung:

    /* ****************************************
         *  token data
         */
        uint32_t Token::maxid = 0;
    
        /*
         * set id
         */
        void Token::setId(uint32_t id) {
            /*
             * set maximum id
             */
            if (maxid < id) {
                maxid = id;
            }
            this->id = id;
        }
    
        /*
         * read Id from String
         */
        void Token::fromString(string s) {
            if (s[0] == '#') {
                setId(atoi(s.substr(1).c_str()));
            }
        }
    
        /*
         * put Id to string
         */
        string Token::toString() {
            string s;
            stringstream ss;
            ss << "#" << id;
            ss >> s;
            return s;
        }
    
        /*
         * create new token
         */
        Token::Token() {
            this->setId(maxid + 1);
        }
    
        /*
         * create new token by id
         */
        Token::Token(uint32_t pId) {
            setId(pId);
        }
    
        /*
         * create new token by string
         */
        Token::Token(string pToken) {
            fromString(pToken);
        }
    
        Token::Token(Token::ptr p) {
            fromString(p->toString());
        }
        /*
         * get token id
         */
        const uint32_t Token::getId() {
            return id;
        }
    
        bool Token::operator==(Token & pToken) {
            return operator==(pToken.getId());
        }
        bool Token::operator==(const uint32_t pId) {
            return this->id == pId;
        }
        bool Token::operator<(Token & pToken) {
            return operator<(pToken.getId());
        }
        bool Token::operator<(const uint32_t pId) {
            return this->id < pId;
        }
        bool Token::isToken(string pString) {
            return (pString[0] == '#');
        }
    


  • Wird auch der richtige Vergleich durchgeführt? Nicht dass du die beiden Pointer vergleichst.



  • Das passiert aber:

    typedef multimap<Token::ptr, Thesis::ptr> idmap;
    

    @Doc Du musst da ein eigenes compare verwenden das die dereferenzierten keys vergleicht.

    Edit: Oder 'globale' compare operatoren für die ptr



  • so weit ich weiß, macht der shared_ptr<>::operator== ein a.get() == b.get()
    hmm.. ja, da werden die pointer verglichen..

    aalso neue operatoren bauen..



  • iirgendwie greift er das nicht an..
    ich dachte mir eigentlich, dass ein

    bool operator== ( Token & a,  Token & b) {
            return a.toString() == b.toString();
        }
    

    ausreicht, reagiert aber kein Stück..

    hm.. öh... hilfe?^^



  • Also erst einmal sollten vergleichsoperatoren const sein und const references verwenden.

    Zweitens benutzt eine map by default den operator < (siehe 3. parameter)

    std::map< 
        KeyType, 
        ValueType, 
        Compare = std::less<KeyType>, 
        Alloc<std::pair< KeyType const, ValueType> 
    >
    

    Edit: Drittens musst du den Operator für Token::ptr erstellen da das ja versucht wird zu vergleichen .get() bei shared_ptr liefert doch den pointer und keine referenz auf das objekt.



  • so na denn aber schönen schrank 🙂
    wer lesen kann ist klar im Vorteil ^^ mit ner Operatorklasse klappts dann auch


Anmelden zum Antworten