Alternative zu "unsigned char AArray[x]" gesucht



  • witte schrieb:

    ... Wenn Du rein mit Iteratoren und ohne Indicies arbeitest sieht das schon wieder ganz anders aus.

    Das sagt sich so schön... Allerdings habe ich keine Idee, wie ich das machen soll. Ich habe eine ListBox und wenn ein Eintrag aus dieser entfernt wird, soll das zugehörige Element des Array auch entfernt werden. Im Array stehen Nummern die identifizieren, welchen Inhalt der ListBox-Eintrag hat.

    Bsp: ListBox hat an Position 3 (ItemIndex= 2) einen Eintrag der entfernt wird.
    Im Array steht in Element 3, welchen Inhalt der Eintrag hat. Da da Eintrag entfernt wird, muss das Element auch entfernt werden - das Array spiegelt sozusagen den Inhalt der ListBox wieder.



  • Ein Vektor erlaubt wahlfreien Zugriff und benötigt daher einen Random Access Iterator. Dieser sollte Iteratorarithmetik unterstützen. Wenn Du also unbedingt einen Einzeiler willst dann mach

    vArray.erase(vArray.begin() + 2);



  • Super, Dankeschön! 🙂 Und was ist daran jetzt schlecht? Warum schlägt akari so eine umständliche Lösung vor? Einfach weil er die Rahmenbedingungen nicht kannte, oder hat sein Vorschlag noch andere Vorteile?

    Ich lösche dann also ein Element jetzt so:

    vArray.erase(vArray.begin() + Var);
    


  • Sein Vorschlag funktioniert für alle Containertypen. Wenn Du beispielsweise ständig die Elemente vertauschst, einfügst und löschst könnte eine std::list besser geeignet sein als ein Vektor mit dem Nachteil, dass sie keinen wahlfreien Zugriff ermöglicht. Sie verwendet einen bidirektionalen Iterator, mein Vorschlag wäre dann unbrauchbar.



  • std::swap(vArray[Var], vArray[Var-1]);
    

    funktioniert auch... Jetzt werd' ich das mal laufen lassen und testen, ob die Werte in vArray stimmen.

    witte schrieb:

    Sein (akari's) Vorschlag funktioniert für alle Containertypen. Wenn Du beispielsweise ständig die Elemente vertauschst, einfügst und löschst könnte eine std::list besser geeignet sein als ein Vektor mit dem Nachteil, dass sie keinen wahlfreien Zugriff ermöglicht. Sie verwendet einen bidirektionalen Iterator, mein Vorschlag wäre dann unbrauchbar.

    Alles, was ich machen wollte funktioniert, aber andererseits vertausche und lösche ich auch Elemente - ich füge allerdings keine Elemente ein, sondern hänge nur an. Wie definierst du "ständig"? Es wird jetzt nicht 1000x in der Minute etwas getauscht oder gelöscht - das passiert 1x pro entsprechender Benutzereingabe (mausklick auf Button). Ist dann vector Ok dafür oder sollte ich trotzdem besser list nehmen?



  • Nimm vector, bei zehn Listboxeinträgen sollte es trivial sein. Wenn Du dann irgendwann "Herr-der-Ringe-Triologie-Videos" in einem Vektor speichern willst und diese ständig umherkopieren willst reden wir nochmal drüber.



  • Juhu! Mein erstes Mal "std::vector" funktioniert 😃

    Vielen Dank akari und witte 👍

    PS: Das mit den Iteratoren hab' ich allerdings noch nicht ganz verstanden - was ist das für eine merkwürdige Lebensform?



  • Hallo

    Iteratoren sind ein weiteres Merkmal der schon genannten Austauschbarkeit von verschiedenen Containertypen. Wenn du zum Beispiel std::vector und std::list vergleichst, wirst du feststellen das std::list konzeptbedingt keinen []-Operator bzw. generell keinen wahlfreien Zugriff bietet.
    Das führt stätestens dann zu Problemen wenn du mal einen Containertyp von vector zu list austauschen willst. Dann must du schlimmstenfalls große Teile deines index-basierenden Programms umschreiben.
    Mit iteratoren hingegen können auch völlig unterschiedliche Containertypen gleich behandelt werden. Insbesondere erlauben diese auch sehr umfangreiche Metaprogrammierungen mit Templates.
    Dieses Thema ist aber wohl zu umfangreich, um in ein paar Sätzen abgehandelt zu werden. Arbeite erstmal weiter mit std::vector, du wirst schon irgendwann an den Punkt kommen wo du die nützlichkeit von Iteratoren verstehst. Nicht zu vergessen das dieses allgemeine, nicht Builder-spezifsche Thema schon in C++ Forum und auch in den Magazinartikeln behandelt wurde.

    bis bald
    akari



  • akari schrieb:

    Iteratoren sind ein weiteres Merkmal der schon genannten Austauschbarkeit von verschiedenen Containertypen. Wenn du zum Beispiel std::vector und std::list vergleichst, wirst du feststellen das std::list konzeptbedingt keinen []-Operator bzw. generell keinen wahlfreien Zugriff bietet.
    Das führt stätestens dann zu Problemen wenn du mal einen Containertyp von vector zu list austauschen willst. Dann must du schlimmstenfalls große Teile deines index-basierenden Programms umschreiben.
    Mit iteratoren hingegen können auch völlig unterschiedliche Containertypen gleich behandelt werden.

    Ok, soweit war mir das schon klar und so steht es ja überall geschrieben.

    akari schrieb:

    Arbeite erstmal weiter mit std::vector, du wirst schon irgendwann an den Punkt kommen wo du die nützlichkeit von Iteratoren verstehst.

    Das ist ja das Problem: Das ich bei Nutzung der STL unbedingt wissen muss WAS Iteratoren sind - um ihre Nützlichkeit weiß ich im Prinzip schon, auch wenn es nur aus der Überlegung heraus ist, dass ich sie brauche um die STL sinnvoll zu nutzen. Du hast mir (und dafür natürlich Danke) jetzt nochmal grob erklärt was die Vorteile und der Sinn von Iteratoren sind. Die für mich wichtige Frage ist aber: Was sind Iteratoren genau? Aber ich werd' mich dazu auf jeden Fall die Tage belesen!

    witte schrieb:

    ... Wenn Du also unbedingt einen Einzeiler willst ...

    Dazu nochmal: Das liest sich, als wäre es nicht erstrebenswert den Quellcode kurz zu halten?! Ich halte das eigentlich so, dass ich Quellcode so kurz wie möglich aber so lang wie nötig schreibe - Somit passt mehr Funktionalität rein, ohne dass es unübersichtlich wird. Ich bin noch lange nicht soweit mir Gedanken über Wiederverwendung von Programmteilen zu machen, dazu sind die Programme die ich zu schreiben habe viel zu klein und von zu geringer Anzahl. Auch gibt es hier niemanden, der meine Programmteile verwenden möchte, da die Kollegen die hier noch (teilweise nur am Rande) programmieren komplett auf C-Style sind und somit mit meinen Programmen schon garnichts mehr anfangen könnten (vom Verständnis her). Vor diesem Hintergrund sollte das doch Ok sein, oder?



  • Kolumbus schrieb:

    akari schrieb:

    Arbeite erstmal weiter mit std::vector, du wirst schon irgendwann an den Punkt kommen wo du die nützlichkeit von Iteratoren verstehst.

    Das ist ja das Problem: Das ich bei Nutzung der STL unbedingt wissen muss WAS Iteratoren sind - um ihre Nützlichkeit weiß ich im Prinzip schon, auch wenn es nur aus der Überlegung heraus ist, dass ich sie brauche um die STL sinnvoll zu nutzen. Du hast mir (und dafür natürlich Danke) jetzt nochmal grob erklärt was die Vorteile und der Sinn von Iteratoren sind. Die für mich wichtige Frage ist aber: Was sind Iteratoren genau? Aber ich werd' mich dazu auf jeden Fall die Tage belesen!

    Das ist ja das schöne an den STL-Containern : Du kannst grade std::vector so benutzen als würdest du mit einem herkömmlichen dynamischen C-Array arbeiten, nur sicherer. Wenn du also erstmal weiter mit Indexen arbeitest machst du nichts falsch. Du must nicht mit Iteratoren arbeiten (hm... nagut wenn du erase anwenden willst dann doch).
    Iteratoren sind transparente Hilfskonstrukte der Container, d.h. ohne Container keine Iteratoren. Am Anfang hilft es wenn du dir einen Iterator als Zeiger vorstellst. Denn wenn du mit C-Arrays arbeitest wirst du vielleicht schon die Pointer-Arithmetik kennen gelernt haben :

    int Array[10]; // Einfaches Array
    int* Pointer = &Array; // Pointer auf das erste Element des Arrays
    int* End = Pointer +10; // Pointer auf des Speicherbereich direkt nach dem letzten Element des Arrays. 
    // Dieser Pointer darf nicht dereferenziert werden, wir brauchen nur seine Adresse als Schluß-Markierung 
    for (; Pointer != End; Pointer++) // Iteration über alle Elemente
    {
      cout << *Pointer << endl; // Ausgabe des Elementes
    }
    

    Iteratoren sind nun Klassen die das Verhalten von Pointern soweit nachbauen. D.h. die Arithmetik-Operatoren (+,-,++,--) und der Dereferenzierungsoperator (*, ->) wurden überladen. Und deshalb sehen Iteration auch sehr ähnlich aus :

    std::vector<int> Array; // Einfaches Array
    std::vector<int>::iterator It = Array.begin(); // Iterator auf das erste Element des Arrays
    std::vector<int>::iterator End = Array.end(); // Iterator auf des Speicherbereich direkt nach dem letzten Element des Arrays. 
    // Dieser Iterator darf nicht dereferenziert werden, wir brauchen nur seine Adresse als Schluß-Markierung 
    for (; It != End; It++) // Iteration über alle Elemente
    {
      cout << *It << endl; // Ausgabe des Elementes
    }
    

    Der Vorteil des Iterators gegenüber dem rohen Pointers ist das sich das Iterator-Konzept auch auf Container anwenden läßt bei dem rohe Pointer-Arithmetik nicht funktioniert (Eben alles außer std::vector).

    witte schrieb:

    ... Wenn Du also unbedingt einen Einzeiler willst ...

    Dazu nochmal: Das liest sich, als wäre es nicht erstrebenswert den Quellcode kurz zu halten?! Ich halte das eigentlich so, dass ich Quellcode so kurz wie möglich aber so lang wie nötig schreibe - Somit passt mehr Funktionalität rein, ohne dass es unübersichtlich wird. Ich bin noch lange nicht soweit mir Gedanken über Wiederverwendung von Programmteilen zu machen, dazu sind die Programme die ich zu schreiben habe viel zu klein und von zu geringer Anzahl. Auch gibt es hier niemanden, der meine Programmteile verwenden möchte, da die Kollegen die hier noch (teilweise nur am Rande) programmieren komplett auf C-Style sind und somit mit meinen Programmen schon garnichts mehr anfangen könnten (vom Verständnis her). Vor diesem Hintergrund sollte das doch Ok sein, oder?

    Selbstverständlich ist es gut kompakten lesbaren Code zu schreiben. In diesem speziellen Fall ist wittes Lösung sicher angebracht. Solange du immer nur ein Element aufeinmal löschen willst läßt sich da nichts mehr optimieren.
    Aber vielleicht hast du ja auch irgendwann mal die Aufgabe eine ganze Reihe von Elementen aufeinmal zu löschen. Wenn du dann für jedes Löschen jeweils einen neuen Iterator aufstellst und weiterschiebst, hast du keinen Vorteil gegenüber dem rohen Array.
    Wenn du aber gleich alle Elemente mit einen Iterator durchgehst und bei zutreffenden Elementen erase anwendest dann bekommst du nämlich sogar noch einen minimalen Geschwindigkeitsvorteil gegenüber einem rohen Array.

    bis bald
    akari



  • Es gibt noch die find() und remove_if Funktionen, mit denen das schon etwas handlicher aussieht:

    std::vector<unsigned int> v;
    
    // alle 5 entfernen
    v.erase( std::remove_if( v.begin(), v.end(), 5 ), v.end() );
    
    // die erste 4 entfernen
    v.erase( std::find( v.begin(), v.end(), 4 ) );
    


  • Vielen Vielen Dank für die ausführlichen Erklärungen akari und Danke für die Ergänzung _DocShoe_! Ich werde ab jetzt versuchen an passenden Stellen immer mit std::vector zu arbeiten. 👍

    MfG


Anmelden zum Antworten