vector hinzufügen ohne objekt zu kopieren (ggf. refcount++)



  • 314159265358979 schrieb:

    Wenn der Default-Move-Ctor das richtige tut, oder du deinen eigenen hast, schon.

    ich habe einen leeren constructor, da ich die Klasse erst mit der InitElement initialisiere...
    ich weis ja nicht, ob std::move das tut, was ich will...er soll das erstellte objekt in den Vector "moven" (also nicht kopieren, sondern verschieben)



  • Ein neues Objekt muss bei push_back auf jeden Fall erstellt werden. Das mit InitElement vergiss mal wieder, das ist Schwachsinn. Member werden im Ctor initialisiert. Ich würde wohl die Variante mit unique_ptr nehmen.



  • mhm...
    muss ich auf noch irgendwas achten, oder kann ich das einfach so verwenden:

    typedef std::vector<std::unique_ptr<TElement>> pElementList;
      pElementList pElements;
    
      unique_ptr<TElement> pE(new TElement());
      pE->InitElement(this,Template,left,top,4,4);//init-code in constructor verlagern
      pElements.push_back(std::move(pE));
    

    stimmt der zugriff? freigegeben wird das TElement ja, wenn die liste zerstört wird, oder? bzw. wenn ich erase aufrufe...kann ich irgendwie elemente ohne iterator löschen? also per index-zugriff (z.b. remove(4) soll das 5.element löschen)?



  • Stimmt so, ja. Ein Element an einer bestimmten Position im vector kannst du löschen durch:

    vec.erase(vec.begin() + n);
    

    Bei vector könnte sowas jedoch langsam sein, da hier alle Elemente hinter dem gelöschten um eine Stelle vorgeschoben werden müssen.



  • 314159265358979 schrieb:

    Bei vector könnte sowas jedoch langsam sein, da hier alle Elemente hinter dem gelöschten um eine Stelle vorgeschoben werden müssen.

    welche Alternativen gäbe es denn? prinzipiell brauche ich ja ein dynamisches array mit Klassen-Elementen.



  • frank schrieb:

    314159265358979 schrieb:

    Bei vector könnte sowas jedoch langsam sein, da hier alle Elemente hinter dem gelöschten um eine Stelle vorgeschoben werden müssen.

    welche Alternativen gäbe es denn? prinzipiell brauche ich ja ein dynamisches array mit Klassen-Elementen.

    Wenn die Reihenfolge im Vektor egal ist, such mal das erase-remove Idiom.



  • nach bisschen suchen zu dem erase/remove kam mir die idee, ich könnte das zu löschende item mit dem letzten tauschen und dann den vector 1 kleiner machen bzw. dann löschen...dann umgehe ich das nachrutschen. da ich die einzelnen Elemente eh per pointer referenziere oder die liste von vorne nach hinten durchgehe (wo mit die reihenfolge egal ist) wäre das eigentlich egal, an welcher stelle ein bestimmtes item ist.

    nur wie tausche ich am elegantesten 2 Items in einem Vector?



  • Guck dir mal std::remove() an.



  • std::remove erwartet eine value (ein int-wert, string,...). kann ich da auch meine unique_ptr entfernen, ohne dass speicherlecks (vom TElement) zurückbleiben?

    wie würde das aussehen?

    ich würde vermuten so in etwa:

    pElements.erase(std::remove(pElements.begin(), pElements.end(), pElements[index]), pElements.end());
    


  • frank schrieb:

    nach bisschen suchen zu dem erase/remove kam mir die idee, ich könnte das zu löschende item mit dem letzten tauschen und dann den vector 1 kleiner machen bzw. dann löschen...dann umgehe ich das nachrutschen. da ich die einzelnen Elemente eh per pointer referenziere oder die liste von vorne nach hinten durchgehe (wo mit die reihenfolge egal ist) wäre das eigentlich egal, an welcher stelle ein bestimmtes item ist.

    nur wie tausche ich am elegantesten 2 Items in einem Vector?

    So wäre es gut:

    template<typename T>
    void delete_element(std::vector<T>& vec, std::size_t index)
    {
      std::swap(vec.at(index), vec.back());
      vec.resize(vec.size() - 1);
    }
    


  • Hallo,
    nachdem der unique_ptr für TElement super funktioniert, wollte ich das ganze auch für die unterklasse TConnection machen...

    kann mir mal jemand verraten, wie man aus diesem Kauderwelsch etwas entnehmen kann?

    $ g++ -Wall -std=c++0x platine.cpp -o platine `pkg-config --cflags gtk+-2.0` `pkg-config --libs gtk+-2.0`
    In file included from /usr/include/c++/4.4/vector:64,
                     from platine.h:3,
                     from platine.cpp:13:
    /usr/include/c++/4.4/bits/unique_ptr.h: In static member function ‘static _ForwardIterator std::__uninitialized_copy<<anonymous> >::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = __gnu_cxx::__normal_iterator<const std::unique_ptr<TConnection, std::default_delete<TConnection> >*, std::vector<std::unique_ptr<TConnection, std::default_delete<TConnection> >, std::allocator<std::unique_ptr<TConnection, std::default_delete<TConnection> > > > >, _ForwardIterator = std::unique_ptr<TConnection, std::default_delete<TConnection> >*, bool <anonymous> = false]’:
    /usr/include/c++/4.4/bits/stl_uninitialized.h:117:   instantiated from ‘_ForwardIterator std::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = __gnu_cxx::__normal_iterator<const std::unique_ptr<TConnection, std::default_delete<TConnection> >*, std::vector<std::unique_ptr<TConnection, std::default_delete<TConnection> >, std::allocator<std::unique_ptr<TConnection, std::default_delete<TConnection> > > > >, _ForwardIterator = std::unique_ptr<TConnection, std::default_delete<TConnection> >*]’
    /usr/include/c++/4.4/bits/stl_uninitialized.h:257:   instantiated from ‘_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, std::allocator<_Tp>&) [with _InputIterator = __gnu_cxx::__normal_iterator<const std::unique_ptr<TConnection, std::default_delete<TConnection> >*, std::vector<std::unique_ptr<TConnection, std::default_delete<TConnection> >, std::allocator<std::unique_ptr<TConnection, std::default_delete<TConnection> > > > >, _ForwardIterator = std::unique_ptr<TConnection, std::default_delete<TConnection> >*, _Tp = std::unique_ptr<TConnection, std::default_delete<TConnection> >]’
    /usr/include/c++/4.4/bits/stl_vector.h:243:   instantiated from ‘std::vector<_Tp, _Alloc>::vector(const std::vector<_Tp, _Alloc>&) [with _Tp = std::unique_ptr<TConnection, std::default_delete<TConnection> >, _Alloc = std::allocator<std::unique_ptr<TConnection, std::default_delete<TConnection> > >]’
    platine.h:199:   instantiated from here
    /usr/include/c++/4.4/bits/unique_ptr.h:214: error: deleted function ‘std::unique_ptr<_Tp, _Tp_Deleter>::unique_ptr(const std::unique_ptr<_Tp, _Tp_Deleter>&) [with _Tp = TConnection, _Tp_Deleter = std::default_delete<TConnection>]’
    /usr/include/c++/4.4/bits/stl_uninitialized.h:74: error: used here
    
    class TConnection
    
    {
      ...
      public:
    
        TConnection(TPlatine *board,TElement *elmt,int ID,string name); //inside TElement
        //TConnection(TPlatine *board,int x,int y,string name); //outside TElement
    
        virtual ~TConnection() {};
    ...
    }
    
    typedef std::vector<std::unique_ptr<TConnection>> pConnectionList;
    
    class TElement
    
    {
    ...
      public:
    
    ...
        pConnectionList pConnections;
    

    der Fehler kommt erst wenn ich das pConnections-Feld in TElement einbaue. bei der reinen typedef nicht. Dachte erst, es liegt an meinen 2 Ctoren, aber der Fehler kommt auch nur mit einem...
    ich habe im code noch nichts, wo ich auf pConnections zugreife (bzw. auskommentiert).



  • Dasselbe wie vorhin, du versuchst irgendwo einen unique_ptr zu kopieren.



  • eben nicht, wenn ich die Zeile im TElement auskommentiere wird fehlerfrei compiliert...ich verwende also nirgendwo das pConnections. somit wird davon auch kein Element kopiert

    die ganzen Zugriffe habe ich schon auskommentiert zur Fehlereingrenzung



  • platine.h Zeile 199.



  • Wenn Du welche Zeile auskommentierst?

    Die Fehlermeldungen sehen so aus, als ob an irgendeiner Stelle versucht würde, ein vector von uninque_ptr-Objekten zu kopieren, möglicherweise auch indirekt (z.B. in einem vom Compiler generierten copy-ctor für TEelement), den du versehentlich irgendwo verwendest.

    Genug geraten.



  • mhm, wenn ich eine pConnectionList in TPlatine definiere (wo die pElementList drin ist) kommen keine Fehler...kommt der fehler evtl. durch die Struktur, dass ich eine Liste von Elementen habe die selbst eine Liste mit connections haben?

    class TConnection {...};
    typedef std::vector<std::unique_ptr<TConnection>> pConnectionList;
    
    class TElement {
    ...
    public
    //pConnectionList pConnections; //funktioniert nicht
    };
    typedef std::vector<std::unique_ptr<TElement>> pElementList;
    
    class TPlatine 
    {
    ...
    private
        pElementList pElements; //funktioniert
        pConnectionList pConnections; //funktioniert
    };
    

    was mir grade auffällt...in TElement ist die Liste public, in TPlatine private...hat das vielleicht damit was zu tun?

    den public zugriff bräuchte ich aber (sonst müsste ich mit zugriffsroutinen schreiben)

    Zeile 199 wäre nur die einleitende Klammer von TElement...trotz pConnectionList im private von TElement kommt der Fehler.

    TElement erzeuge ich nur über TPlatine::AddElement, welche so aussieht:

    void TPlatine::AddElement(std::string Template,int left,int top)
    
    {
      int width=4;
    
      std::unique_ptr<TElement> pE(new TElement(this,Template,left,top,width,4));
      pElements.push_back(std::move(pE));
    }
    

    ansonsten hat nur TConnection noch ein feld, welches so definiert ist und zugewiesen wird:

    TElement *fElement;
    TConnection::TConnection(TPlatine *board,TElement *elmt,int ID,string name)
    
    {
    
      fElement=elmt;
    }
    


  • Zeig doch mal bitte den Code um Zeile 199 her, so kommen wir nicht weiter...



  • class TElement
    { //Zeile 199, fehler kommt aktuell auch noch in der Zeile (platine.h:199:   instantiated from here)
      private:
        int fLeft,fTop,fWidth,fHeight;
        std::string fTemplate,fPrefix;
        //int fNumber;
        std::string fValue;//,fUnit;
        int fDirection;
        TPlatine *fPlatine;
        pConnectionList pConnections;
      protected:
    

    habe den aktuellen code mal hier hochgeladen: http://dl.dropbox.com/u/3228629/platine.zip



  • Aus Spass kannst du bei TElement ja mal einen privaten undefinierten Copy-Ctor hinzufügen; denn kopierbar ist das Ding nicht (wegen des pConnection-Vektors) und so kann ein solcher Fehler früher abgefangen werden. Das fliegt Dir dann nicht erst irgendwo im Code von vector<unique_ptr> um die Ohren.



  • meinst du einen leeren copy-constructor?

    also so:

    class TElement
    {
      private:
    ...
        TElement(const TElement& e) {};   // copy constructor
    

    da bekomme ich nen Fehler

    platine.h: In member function ‘bool TPlatine::OnRedraw(GdkEventExpose*)’:
    platine.h:210: error: ‘TElement::TElement(const TElement&)’ is private
    platine.cpp:555: error: within this context
    platine.cpp:555: error: initializing argument 1 of ‘void TPlatine::DrawElement(TElement)’

    zeile 210 ist die definition des copy-CTors siehe oben

    evtl ist in Zeile 555 schon der Hund begraben...

    hier der code-Ausschnitt:

    for (unsigned int i=0; i<pElements.size();i++)
        {
          DrawElement(*pElements[i]); //zeile 555
        }
    

Anmelden zum Antworten