delete auf ein Vectorelement



  • Tritt dein Problem wirklich auch im oben geposteten Beispiel auf? Da kann es nämlich nicht an den Iteratoren liegen. Falls ja, würde ich trotzdem mal genau debuggen und schauen, ob zum Beispiel ein ungültiger Zeiger freigegeben wird oder so.



  • mase schrieb:

    Und wie kann ich das Problem mit den ungültigen Iteratoren umgehen?

    mit std::list...

    bb



  • indem man den Rückgabewert von erase nutzt.



  • Naja, nach dem erase() wird bei mir gar kein Iterator mehr verwendet.
    Vor dem nächsten Aufruf von erase() wird der Iterator neu initialisiert
    mit Streams.begin().



  • Ich poste mal etwas mehr Code.

    Die Streams werden so in den Vector eingefügt:

    Streams.push_back(new cStream);
    

    Wenn ein Stream entfernt werden soll, wird folgende Funktion aufgerufen:

    void RemoveStream(int _StreamNumber)
    {
        //remove stream completely
        Streams[_StreamNumber]->CloseStream();
        std::vector<cStream*>::iterator Iter = Streams.begin();
        for (int i = 0; i < _StreamNumber; i++)
        {
            Iter++;
        }
    
        delete Streams[_StreamNumber];
        Streams.erase(Iter);
        NumberOfStreams--;
    
        return;
    }
    

    _StreamNumber ist der entsprechenden Bezeichner.
    Das CloseStream() der cStream-Klasse löscht nichts. Es wird lediglich die
    Serververbindung beendet.
    Das delete hier führt zu einem Segfault.



  • Ich hab es jetzt mal mit einem Smartpointer in einem Pointervector von
    libboost probiert:

    Streams.push_back(boost::shared_ptr<cStream>(new cStream));
    

    Der Vector ist so deklariert:

    boost::ptr_vector<boost::shared_ptr<cStream> > Streams;
    

    Doch es kompiliert nicht.
    By the way: Ist es besser, anstatt erase() ein release() aufzurufen, wenn
    das Objekt auch zerstört werden soll?
    Das ist die Fehlermeldung des Compilers:

    error: no matching function for call to 'boost::ptr_vector<boost::shared_ptr<cStream>, boost::heap_clone_allocator, 
    std::allocator<void*> >::push_back(boost::shared_ptr<cStream>)'
    /usr/include/boost/ptr_container/ptr_sequence_adapter.hpp:178: note: candidates are: void boost::ptr_sequence_adapter<T, VoidPtrSeq,
    CloneAllocator>::push_back(typename boost::ptr_container_detail::reversible_ptr_container<boost::ptr_container
    _detail::sequence_config<T, VoidPtrSeq>, CloneAllocator>::value_type) [with T
    = boost::shared_ptr<cStream>, VoidPtrSeq = std::vector<void*, std::allocator<void*> >, CloneAllocator = boost::heap_clone_allocator]
    


  • Wieso ptr_vector und shared_ptr ? Entweder oder, eins davon reicht. Ich würde ptr_vector empfehlen, da du mit dem Smart-Pointer mit grosser Wahrscheinlichkeit Overhead hast, den du gar nicht benötigst.



  • Ich hab mich für den ptc_vector entschieden. Seh ich das richtig, dass die
    Elemente darin automatisch dereferenziert werden, ich also mit dem . Operator
    zugreifen muss, anstatt ->?
    Aber folgender Aufruf führt zu einem Segfault:

    boost::ptr_vector<cStream>::iterator Iter = Streams.begin();
        for (int i = 0; i < _StreamNumber; i++)
        {
            Iter++;
        }
    
        Streams.erase(Iter);
    


  • Du versuchst wahrscheinlich, ein Element zu löschen, das bereits jenseits der Sequenz liegt.

    Normalerweise iteriert man aber auch anders. 😉

    for (boost::ptr_vector<cStream>::iterator iter = Streams.begin(); i != Streams.end(); ++i) // wichtig: nicht i++
    {
       // Mache für jedes Element etwas
    }
    

    Wenn du allerdings nur ein Element an einem bestimmten Index löschen willst, kannst du das bei Random-Access-Containern auch so machen:

    Streams.erase(Streams.begin() + Index);
    

    Aber sei dir bewusst, dass Zeiger, Referenzen und Iteratoren auf Elemente des Containers anschliessend ungültig werden können.



  • Nexus schrieb:

    Du versuchst wahrscheinlich, ein Element zu löschen, das bereits jenseits der Sequenz liegt.

    Normalerweise iteriert man aber auch anders. 😉

    for (boost::ptr_vector<cStream>::iterator iter = Streams.begin(); i != Streams.end(); ++i) // wichtig: nicht i++
    {
       // Mache für jedes Element etwas
    }
    

    Wenn du allerdings nur ein Element an einem bestimmten Index löschen willst, kannst du das bei Random-Access-Containern auch so machen:

    Streams.erase(Streams.begin() + Index);
    

    Aber sei dir bewusst, dass Zeiger, Referenzen und Iteratoren auf Elemente des Containers anschliessend ungültig werden können.

    Ich hab's nach der 2. Methode gemacht. Ich hab jedoch gelesen, dass release(),
    anstatt erase() aufgerufen werden sollte, da so auch der Speicher für das
    Element freigegeben würde. Mein Ziel war ja, dass nicht nur das Element
    aus dem Vector entfernt wird, sondern auch ein delete für das Element auf-
    gerufen wird.
    Seh ich das richtig:
    Beim std::vector muss als Typ <cStream*> angegeben werden, beim
    boost::ptr_vector ein <cStream>, sonst wären es ja Zeiger auf Zeiger.
    Der Elementzugriff erfolgt mit Punktoperator, anstatt ->.



  • ja.


Anmelden zum Antworten