vektoren kapazität



  • hi
    ich habe folgendes problem...

    ich bin gerade dabei mich genauer mit den stl-containern , speziell gerade mit vektoren ausseinander zusetzten.
    nun bin ich auf folgendes problem gestoßen:

    ich habe gelesen das ein vektor immer eine größe und eine kapazität braucht.
    nach den ersten übungen/test mit 1d vektoren wollte ich nun einen 2d vektor.
    dazu habe ich mich wieder bei google belesen wie der syntax für soetwas lautet.
    nun habe ich das hier gefunden und es noch auf meine bedürfnisse angepasst:

    std::vector<std::vector<QString> > vec_2darray_qstrings;
    
            int hoehe=19;
            int breite=5;
    
            vec_2darray_qstrings.resize(hoehe);
    
            for(int i = 0; i < hoehe; ++i)
            {
                vec_2darray_qstrings[i].resize(breite);
            }
    
            vec_2darray_qstrings[1][2]="test";
            std::cout << vec_2darray_qstrings[1][2] << std::endl;
    

    wenn ich jetzt die vielen tutorials und referenzen richtig verstanden habe erweitert diese schleife meine vektoren erst im nachhinein.
    nun meine fragen:

    1. kann man den vektor vll auch direkt auf diese größe setzten ohne resize();?
    wenn ja wie?

    2. hier muss /bzw. wird im beispiel keine kapazität mit angegeben?
    ist das ein fehler? muss man das nicht immer die kapazität mit angeben?

    und wenn ihr vll noch weiter tipps, hinweise oder interessante links zu vektoren habt könnt ihr die mir auch gerne mal posten 🙂 ...

    lg



  • Du brauchst resize nicht unbedingt. Fürs erste würde es genügen, mittels vector::push_back() einfach Elemente hinzuzufügen. Der Vektor passt dann seine Größe automatisch an:

    vector<int> test;
    
    cout << test.size() << '\n';
    
    for(int i = 3; i < 8; ++i)
    {
       test.push_back(i);
       cout << test.size() << '\n';
    }
    
    for(int i = 0; i < test.size(); ++i)
       cout << "test[" << i << "] = " << test[i] << '\n';
    


  • Du hast kein 2d-Array (oder Vector) definiert, sondern einen Vector von Vectoren. Boost.MultiArray ist vielleicht das was du suchst.

    Ansonsten: Einen std::vector kann man ohne Größenangabe anlegen. Das ist der eigentliche Witz daran. Elemente werden mit push_back oder emplace_back eingefügt und der Vector passt sich automatisch an.



  • Belli schrieb:

    Du brauchst resize nicht unbedingt. Fürs erste würde es genügen, mittels vector::push_back() einfach Elemente hinzuzufügen. Der Vektor passt dann seine Größe automatisch an:

    vector<int> test;
    
    cout << test.size() << '\n';
    
    for(int i = 3; i < 8; ++i)
    {
       test.push_back(i);
       cout << test.size() << '\n';
    }
    
    for(int i = 0; i < test.size(); ++i)
       cout << "test[" << i << "] = " << test[i] << '\n';
    

    ok, wäre ja aber ähnlich dem resize...

    kann ich nicht sagen "mein vektor hat die größe [100][100] anstatt das in einer schleife zu erweitern? 🙄
    wenn ja wie? -> direkt an meinem vektor im vektor...

    oder macht das eh keinen unterschied?
    ob ich den stätig erweitere oder auf einmal "setze" ?
    finde dazu leider keine infos... 😞

    ich hatte an soetwas gedacht... hier geht das ja auch...

    // inserting into a vector
    #include <iostream>
    #include <vector>
    
    int main ()
    {
      std::vector<int> myvector (3,100);
      std::vector<int>::iterator it;
    
      it = myvector.begin();
      it = myvector.insert ( it , 200 );
    
      myvector.insert (it,2,300);
    
      // "it" no longer valid, get a new one:
      it = myvector.begin();
    
      std::vector<int> anothervector (2,400); //ich meine soetwas nur für einen vektor im vektor?
      myvector.insert (it+2,anothervector.begin(),anothervector.end());
    
      int myarray [] = { 501,502,503 };
      myvector.insert (myvector.begin(), myarray, myarray+3);
    
      std::cout << "myvector contains:";
      for (it=myvector.begin(); it<myvector.end(); it++)
        std::cout << ' ' << *it;
      std::cout << '\n';
    
      return 0;
    }
    

    würde mir eig gerne die schleife sparen und das verändern des vektors wenns nicht unbeding sein muss...
    weiß jemand wie das funktioniert? 😕



  • .reserve() reserviert nur Speicher, damit sich der Container auf die angegebene Größe vergrößern lässt, ohne dass DANN jedes Mal sein Inhalt umkopiert werden muss. Dies erfolgt dann nämlich bereits beim reserve()-Aufruf (sofern notwendig). Die size() bleibt gleich und es werden keine Element-Objekte erzeugt. Edit: capacity() it nur zum Abrufen.

    .resize() dagegen vergrößert den Container und füllt ihn mit den entsprechenden Objekten auf (diese werden über ihren Default-Constructor erzeugt).

    guckst du:
    http://www.cplusplus.com/reference/vector/vector/resize/
    http://www.cplusplus.com/reference/vector/vector/capacity/

    Ja, man kann einen 2D-Vector bereits mit einer bestimmten Größe konstruieren, der dann ebenfalls Objekte enthält. Die inneren 2D-Vectoren gehen so nicht.
    http://www.cplusplus.com/reference/vector/vector/vector/



  • Ein Tip noch: Wenn ein Vector wie hier benutzt werden soll, um x- und y-Koordinaten abzubilden, z.B. wie bei einer Matrix, kann es ggf. auch aus Performancegründen geschickter sein, dass man im 2D bleibt und den Elementzugriff jeweils durch myVector[x*(Y-größe) + y] vornimmt. Man bildet sozusagen alle Elemente hintereinander ab. Dann braucht es kein vector< vector < T > > .

    Nachteil: Die nachträgliche Vergrößerung einer Richtung geht dann natürlich nicht mehr, aber immerhin kann man das Ding ohne Schleifen initialisieren.

    Kannst ja eine einfache Wrapper-Klasse schreiben, die diesen Elementzugriff unter der Haube erledigt, aber das gibt's sicher schon zig-fach.

    edit: Formel für Elementzugriff falsch



  • minastaros schrieb:

    .capacity() reserviert nur Speicher, damit sich der Container auf die angegebene Größe vergrößern lässt, ohne dass DANN jedes Mal sein Inhalt umkopiert werden muss. Dies erfolgt dann nämlich bereits beim capacity()-Aufruf (sofern notwendig). Die size() bleibt gleich und es werden keine Element-Objekte erzeugt.

    .resize() dagegen vergrößert den Container und füllt ihn mit den entsprechenden Objekten auf (diese werden über ihren Default-Constructor erzeugt).

    guckst du:
    http://www.cplusplus.com/reference/vector/vector/resize/
    http://www.cplusplus.com/reference/vector/vector/capacity/

    Ja, man kann einen 2D-Vector bereits mit einer bestimmten Größe konstruieren, der dann ebenfalls Objekte enthält. Die inneren 2D-Vectoren gehen so nicht.
    http://www.cplusplus.com/reference/vector/vector/vector/

    also würde die kapazität bei mir wenn ich die gar nicht setzte einfach durch das "resize()" "mitwachsen" ...
    aber der vektor würde immer umkopiert wenn ich dies tue... richrtig?
    also wäre es schöner die kapazität zusetzten wenn ich diese kenne... oder?
    wie ist/wäre hier die gänige praxis?

    ok das hat mir viel geholfen 🙂 :
    http://www.cplusplus.com/reference/vector/vector/capacity/

    da hääte ich auch selbst drauf kommen können ... 😃
    vielen dank ... 🙂

    wie mache ich das bei einem vektor im vektor... ?
    http://www.cplusplus.com/reference/vector/vector/vector/

    (das hatte ich schon gefunden... nur ich weiß nicht wie ich das auf einen vektor im vektor anwenden kann ... 😞 )

    sry für meine vll blöden fragen...
    ich hab i.wie das gefühl ich stehe aufn schlauch... 😞

    vielen dank schonmal an alle die so schnell geantwortet haben 🙂



  • minastaros schrieb:

    Ein Tip noch: Wenn ein Vector wie hier benutzt werden soll, um x- und y-Koordinaten abzubilden, z.B. wie bei einer Matrix, kann es ggf. auch aus Performancegründen geschickter sein, dass man im 2D bleibt und den Elementzugriff jeweils durch myVector[x*y] vornimmt. Man bildet sozusagen alle Elemente hintereinander ab. Dann braucht es kein vector< vector < T > > .

    Nachteil: Die nachträgliche Vergrößerung einer Richtung geht dann natürlich nicht mehr, aber immerhin kann man das Ding ohne Schleifen initialisieren.

    Kannst ja eine einfache Wrapper-Klasse schreiben, die diesen Elementzugriff unter der Haube erledigt, aber das gibt's sicher schon zig-fach.

    guter tipp vielen dank, jedoch brauche ich für die funktionalität direkt die 2d erweiterbarkeit...

    aber ich weiß z.b. am anfang das ich y-10 datensätze hab...
    und x - 5 ... (beispiel)...
    dann würde ich den vektor "direkt mit dieser kapazität" setzen...

    dann kann ich diesen füllen mit werten und danach will ich sozusagen "warten" und falls es drauf ankommt dann den vektor wieder verkleinern oder ggf. vergößern...

    im vektor hab ich dann alle "werte" in einer array/tabellen ähnlichen struktur, um dann mit den werten weiter zuarbeiten und diese später direkt in dieser tabellen ähnlichen struktur wieder "herauszuschreiben..." 🙄

    oder sollte ich hier einfach meinen vektor wachsen lassen oder versuchen die kapazität am anfang erstmal auf die "startparameter" zu setzen?
    oder spielt das gar keine wirkliche rolle...?
    wie wäre ein praktisches vorgehen in so einem fall?



  • vektor schrieb:

    wie wäre ein praktisches vorgehen in so einem fall?

    Wenn Du von Anfang an weißt, dass Dein Vektor 1 Mio. Einträge haben wird, dann mag es performanter sein, diese Größe einmal per resize zu setzen, damit nicht ständig Speicher neu allokiert und Daten umkopiert werden müssen.

    Wenn es abe nur um ein paar tausend Einträge geht, würde ich einfach bei Bedarf mittels push_back weitere Einträge anhängen.

    Du schreibst wiederholt, Du willst Dir eine/die Schleife sparen ... wie willst Du Deinen Vektor denn befüllen?



  • vektor schrieb:

    also würde die kapazität bei mir wenn ich die gar nicht setzte einfach durch das "resize()" "mitwachsen" ...
    aber der vektor würde immer umkopiert wenn ich dies tue... richrtig?
    also wäre es schöner die kapazität zusetzten wenn ich diese kenne... oder?

    Ein vector (und die meisten anderen Container, z.B. auch std::string) "wächst" automatisch mit, wenn Elemente angefügt werden. Normalerweise brauchst du gar kein reserve() von Hand auszuführen.
    Richtig, wenn der reservierte Speicher zu Ende ist, wird woanders ein größeres Stück reserviert und die Inhalte umkopiert*). Dabei wird der Platz nicht jedes Mal nur um 1 Element vergrößert, sondern gleich ein bisschen mehr. Zum Beispiel das Doppelte der aktuellen Länge, oder das 1,5-fache, je nach Implementierung der Bibliothek.

    😉 Im Falle der Strings betrifft dies allerdings "nur" die relativ kleinen Verwaltungsobjekte (die auf die eigentlichen String-Inhalte zeigen). Die Strings selbst bleiben an Ort und Stelle. Meistens.

    Du wirst allerdings nicht drum herumkommen, bei jeder Größenänderung die Größen der inneren Vectoren synchron zu halten, vor allem, wenn du dort bei einem ein Element anfügst! Dann müssen, wenn das Ding eine Tabelle bleiben soll, auch die anderen mit resize() (denn es geht ja jetzt um die echte Arbeitsgröße) nachgezogen werden.

    Da ich die vorgeschlagene boost-Klasse nicht kenne, könnte ich mir fast eine eigene 2D-Vector-Klasse vorstellen, die sich die Gesamtgröße in x- und y-Richtung merkt. Man könnte dann eine Art "Resize-on-demand" einfügen, d.h.: wenn zu einem der inneren Vectoren ein Element angefügt wird, wird zunächst nur dieser eine Vector vergrößert (nennen wir das die y-Richtung); y wächst also um 1. Erst wenn später in einem anderen inneren Vector (der noch kleiner ist) ein Element mit diesem Index gesetzt oder gelesen wird, wird dieser Vector auf den aktuellen y-Wert vergrößert. Dadurch verteilt man den Aufwand, jedes Mal alle inneren Vectoren nachzuziehen auf den Moment, wo sie tatsächlich benötigt werden. Das wäre für den Aufrufer transparent.

    Aber wie mit allem: Es kommt immer auf den Anwendungsfall an. Was willst du mit der Tabelle eigentlich machen? D.h. wie häufig werden Erweiterungen in x- oder y-Richtung zur Laufzeit zu erwarten sein?

    PS: beachte mein Edit im Post weiter oben. Ich hatte reserve() und capacity() auf die Schnelle verwechselt. Das eine ist zum Ändern, das andere zum Auslesen.


  • Mod

    minastaros schrieb:

    😉 Im Falle der Strings betrifft dies allerdings "nur" die relativ kleinen Verwaltungsobjekte (die auf die eigentlichen String-Inhalte zeigen). Die Strings selbst bleiben an Ort und Stelle. Meistens.

    Wie willst du das denn schaffen? Ein string ist garantiert zusammenhängend, keine deque oder ähnliches.



  • SeppJ schrieb:

    minastaros schrieb:

    😉 Im Falle der Strings betrifft dies allerdings "nur" die relativ kleinen Verwaltungsobjekte (die auf die eigentlichen String-Inhalte zeigen). Die Strings selbst bleiben an Ort und Stelle. Meistens.

    Wie willst du das denn schaffen? Ein string ist garantiert zusammenhängend, keine deque oder ähnliches.

    OK, Missverständnis: ich hatte die std::vector<std::vector<QString> > , wie sie im ersten Post stehen, im Kopf. Wenn man hier den inneren vector vergrößert, bleiben die String-Texte an Ort und Stelle und müssen nicht durch die Gegend kopiert werden (Thema Allocator), im Gegensatz zum vector<int> .
    Betrifft natürlich nicht den string als solchen; wenn man den verlängert, verschiebt sich der Inhalt, ganz klar.
    Danke für den Hinweis!



  • minastaros schrieb:

    vektor schrieb:

    also würde die kapazität bei mir wenn ich die gar nicht setzte einfach durch das "resize()" "mitwachsen" ...
    aber der vektor würde immer umkopiert wenn ich dies tue... richrtig?
    also wäre es schöner die kapazität zusetzten wenn ich diese kenne... oder?

    Ein vector (und die meisten anderen Container, z.B. auch std::string) "wächst" automatisch mit, wenn Elemente angefügt werden. Normalerweise brauchst du gar kein reserve() von Hand auszuführen.
    Richtig, wenn der reservierte Speicher zu Ende ist, wird woanders ein größeres Stück reserviert und die Inhalte umkopiert*). Dabei wird der Platz nicht jedes Mal nur um 1 Element vergrößert, sondern gleich ein bisschen mehr. Zum Beispiel das Doppelte der aktuellen Länge, oder das 1,5-fache, je nach Implementierung der Bibliothek.

    😉 Im Falle der Strings betrifft dies allerdings "nur" die relativ kleinen Verwaltungsobjekte (die auf die eigentlichen String-Inhalte zeigen). Die Strings selbst bleiben an Ort und Stelle. Meistens.

    Du wirst allerdings nicht drum herumkommen, bei jeder Größenänderung die Größen der inneren Vectoren synchron zu halten, vor allem, wenn du dort bei einem ein Element anfügst! Dann müssen, wenn das Ding eine Tabelle bleiben soll, auch die anderen mit resize() (denn es geht ja jetzt um die echte Arbeitsgröße) nachgezogen werden.

    Da ich die vorgeschlagene boost-Klasse nicht kenne, könnte ich mir fast eine eigene 2D-Vector-Klasse vorstellen, die sich die Gesamtgröße in x- und y-Richtung merkt. Man könnte dann eine Art "Resize-on-demand" einfügen, d.h.: wenn zu einem der inneren Vectoren ein Element angefügt wird, wird zunächst nur dieser eine Vector vergrößert (nennen wir das die y-Richtung); y wächst also um 1. Erst wenn später in einem anderen inneren Vector (der noch kleiner ist) ein Element mit diesem Index gesetzt oder gelesen wird, wird dieser Vector auf den aktuellen y-Wert vergrößert. Dadurch verteilt man den Aufwand, jedes Mal alle inneren Vectoren nachzuziehen auf den Moment, wo sie tatsächlich benötigt werden. Das wäre für den Aufrufer transparent.

    Aber wie mit allem: Es kommt immer auf den Anwendungsfall an. Was willst du mit der Tabelle eigentlich machen? D.h. wie häufig werden Erweiterungen in x- oder y-Richtung zur Laufzeit zu erwarten sein?

    PS: beachte mein Edit im Post weiter oben. Ich hatte reserve() und capacity() auf die Schnelle verwechselt. Das eine ist zum Ändern, das andere zum Auslesen.

    ok vielen dank... 🙂

    ich möchte eine CSV-Datei auslesen...
    ich weiß aber nicht genau wie viele spalten und zeilen sie hat(nur das die csv nicht kleiner ist als 5*19 )...
    möchte die werte aber jeden direkt ansprechen später dann über den vektor... 😃

    also könnte ich den vektor dann direkt auf 5*19 mit resize() setzen damit er nicht "umkopiert" werden muss(außer evt. die csv ist doch größer)... wäre das korekt? 🙂

    und die kapazität wird mit dem resize() automatisch gesetzt oder muss ich die noch setzten ? 🙂

    std::vector<std::vector<QString> > vec_2darray_qstrings;
    
            int hoehe=19;
            int breite=5;
    
            vec_2darray_qstrings.resize(hoehe);
    
            for(int i = 0; i < hoehe; ++i)
            {
                vec_2darray_qstrings[i].resize(breite);
            }
    

    und wenn ich dann feststelle ich brauche doch mehr platz, das ich den vektor dann vergrößern würde?

    vielen dank für die antwoten 🙂


  • Mod

    Du solltest nicht den Eindruck bekommen, dass eine Neuallokierung des vectors irgendwie langsam wäre. Der Effekt von reserve oder einem vorzeitigen resize ist, wenn überhaupt, eher gering.

    PS: Und resize vergrößert natürlich auch die Kapazität. Wie sollte das sonst funktionieren? 😕



  • SeppJ schrieb:

    Du solltest nicht den Eindruck bekommen, dass eine Neuallokierung des vectors irgendwie langsam wäre. Der Effekt von reserve oder einem vorzeitigen resize ist, wenn überhaupt, eher gering.

    PS: Und resize vergrößert natürlich auch die Kapazität. Wie sollte das sonst funktionieren? 😕

    gut, wollte nur nochmal sicher gehen... 🙂
    keine ahnung ... 🙂 deswegen frag ich ja... 😃
    aber ist eig schon logisch ... 🙄

    meine frage ist beantwortet bzw. mein problem gelöst... 😃
    vielen dank an alle die geantwortet haben 😃

    lg



  • minastaros schrieb:

    OK, Missverständnis: ich hatte die std::vector<std::vector<QString> > , wie sie im ersten Post stehen, im Kopf. Wenn man hier den inneren vector vergrößert, bleiben die String-Texte an Ort und Stelle und müssen nicht durch die Gegend kopiert werden (Thema Allocator), im Gegensatz zum vector<int> .

    Auch da wäre ich mir nicht so sicher. Hab schon oft String-Klassen mit small string optimization gesehen.


Anmelden zum Antworten