std::vector oder Arrays?



  • Hallo, bin am C++ lernen und lese häufig alle möglichen Threads hier, und mir ist aufgefallen, dass anstatt Arrays immer zu std::vector geraten wird. Wollte mir in meiner Lernphase als nächstes mal die Arrays anschauen, die ich auch aus Java etc. kenne, aber es wurde hier im Forum immer eher zu std::vector geraten. Habe mich da auch mal eingelesen, geht zwar auch um Templates, mit denen ich noch nicht vertraut bin, jedoch sieht die Funktionsweise recht simpel aus.
    Hätte dazu zwei Fragen:
    - Welche Vor-/Nachteile hat std::vector und sollte man die "normalen" Arrays zuerst beherrschen, bevor man zu std::vector kommt?
    - Hat jemand eine gute Erklärung zur Funktionsweise von std::vector?

    Danke für eure Antworten!



  • Arrays reservieren ihren Speicher auf dem Stack. Das ist sehr effizient und kann nicht fehlschlagen. Allerdings muss man die Größe dafür in C++ zur Compilezeit kennen. Und auf dem Stack ist normalerweise nicht so viel Platz (kommt auf dein Host-System an), wenn du das Array also zu groß machst kann es schon fehlschlagen. Das failt dann auch gleich so hart, dass du nichts dagegen machen kannst. Dein Programm wird einfach beendet. std::vector reserviert den Speicher auf dem Heap. Da ist sehr viel Platz, das kann aber fehlschlagen. Dann fliegt ein std::bad_alloc. Wenn du ein kleines Array haben willst bei dem die Größe zur Compilezeit feststeht spricht auch nichts dagegen. Wovon hier viele abraten ist eher

    int* arr = new int[500];
    // Do stuff
    delete[] arr;
    

    weil man an das delete[] denken muss, und man ein Speicherleck bekommt wenn man die Funktion frühzeitig verlässt (z.B. weil eine Exception fliegt). Siehe auch RAII. (Google)



  • Selbst in Java gibt es die Richtlinie, lieber List<T> statt T[] zu nehmen, weil Arrays nicht typsicher sind.

    In C++ ist das Problem ein anderes: Arrays speichern ihre Länge nicht mit und sind vor allem nicht exceptionsicher. Das heisst

    int * array = new array[n];
    f(array, n);
    delete[] array;
    

    hat einen Speicherleak, weil f eine Exception werfen könnte und dann array nicht freigegeben wird.

    Zwar würde das mit try/catch gehen

    int * array = new array[n];
    try { f(array, n); }
    catch (...) { delete[] array; throw; }
    delete[] array;
    

    aber das ist unpraktisch und wird mit zunehmender Anzahl Arrays, Funktionsaufrufen und returns immer komplexer bis unmöglich.

    Diese Probleme hat std::vector nicht.

    std::vector<int> array(n);
    f(array); // vector merkt sich die Länge
    // Speicher wird automatisch freigegeben
    

    Ein Vektor verhält sich sonst wie ein Array (Zugriff mit []) und hat ein paar weiter Features (vergrössert sich bei Bedarf).

    Eine gute (wenn auch etwas komplizierte) Referenz ist hier: http://en.cppreference.com/w/cpp/container/vector
    (von http://cplusplus.com ist abzuraten)

    Aber C++ lernt man besser mit einem Buch, und in dem steht sicher auch etwas über Vektor drin.



  • std::vector und "normale Arrays" sind zwei grundverschiedene Dinge. Ein normales Array hat eine fixe, statische Größe, std::vector kann seine Größe dagegen zur Laufzeit ändern. std::vector ist kein Ersatz für normale Arrays, sondern kapselt new[] und delete[]. Arrays und std::vector stehen nicht in Konkurrenz zueinander, sondern ergänzen sich. Imo sind normale Arrays wesentliche Grundlage und essentiell für das Verständnis der Sprache. Wenn du Arrays dann einigermaßen verstanden hast, kannst du std::array benutzen, um den teilweise sehr obskuren Eigenheiten von normalen Arrays aus dem Weg zu gehen. Auch sollte imo noch std::unique_ptr erwähnt werden. Die Größe von normalen Arrays und std::array wird fix zur Compiletime festgelegt, std::vector liefert ein Array, dessen Größe dynamisch, während das Programm läuft, festgelegt und auch angepasst/geändert werden kann und std::unique_ptr kann als Array mit zur Laufzeit festgelegter, aber nichtmehr änderbarer Größe benutzt werden...



  • anni schrieb:

    Eine gute (wenn auch etwas komplizierte) Referenz

    Wieso kompliziert?

    (von http://cplusplus.com ist abzuraten)

    Weil? Also das wundert mich stark, die Referenz ist eigentlich recht komplett, richtig und gut geschrieben. Lediglich C++11 ist da kürzer gefasst, aber wen juckt das, dafür gibt es ja die andere.

    P.S.: Er meinte mit normalen Arrays auch die normalen Stackarrays, die cooky aufgriff, nicht die Freispeicher-Dinger die man allokieren und freigeben muss.
    Die normalen sind voll in Ordnung. Sie sind sozusagen Exception-Safe, speichern ihre Größe, und solange man weiß was man tut und nicht viele Extras braucht sind sie sogar in keinster Weise schlechter als ein vector und funktionieren natürlich mit allen STL-Algos.

    Auch sollte imo noch std::unique_ptr erwähnt werden.

    boost::scoped_array 🤡



  • Sone schrieb:

    Auch sollte imo noch std::unique_ptr erwähnt werden.

    boost::scoped_array 🤡

    Ich seh keinen Grund, sich wegen sowas eine Abhängigkeit wie boost einzuhandeln...



  • Mit "normale Arrays" meinte ich auch sowas wie

    int xyz[]; int abc[3] = {1, 2, 3};
    

    . Das Schlüsselwörtchen "new" kenne ich quasi noch gar nicht. 😉 Aber jetzt ist mir das ganze etwas klarer geworden, ich dachte std::vector ist sozusagen eine Ablösung für diesen normalen Array, aber das scheint ja nicht so zu sein 🙂



  • Ne, der Ersatz ist std::array.



  • dot schrieb:

    Sone schrieb:

    Auch sollte imo noch std::unique_ptr erwähnt werden.

    boost::scoped_array 🤡

    Ich seh keinen Grund, sich wegen sowas eine Abhängigkeit wie boost einzuhandeln...

    Ach, jetzt komm. Wer hat schon nicht Boost in alle seiner Projekte eingebunden.

    , ich dachte std::vector ist sozusagen eine Ablösung für diesen normalen Array

    Nö, std::vector ist die "Ablösung" für new [] / delete [] .



  • Sone schrieb:

    dot schrieb:

    Sone schrieb:

    Auch sollte imo noch std::unique_ptr erwähnt werden.

    boost::scoped_array 🤡

    Ich seh keinen Grund, sich wegen sowas eine Abhängigkeit wie boost einzuhandeln...

    Ach, jetzt komm. Wer hat schon nicht Boost in alle seiner Projekte eingebunden.

    ich



  • ich



  • Na nun streitet euch doch nicht wegen Boost, soweit bin ich eh lange noch nicht 😃
    Bedanke mich für eure ausführliche Hilfe 😉



  • Kein boost hier.



  • dot schrieb:

    Sone schrieb:

    dot schrieb:

    Sone schrieb:

    Auch sollte imo noch std::unique_ptr erwähnt werden.

    boost::scoped_array 🤡

    Ich seh keinen Grund, sich wegen sowas eine Abhängigkeit wie boost einzuhandeln...

    Ach, jetzt komm. Wer hat schon nicht Boost in alle seiner Projekte eingebunden.

    ich

    und ich 😃

    Zumal ja nun shared_ptr und andere lustige Spielzeuge im Standard sind... 👍



  • Belli schrieb:

    Kein boost hier.

    Och, jetzt komm. 😃



  • hat einen Speicherleak, weil f eine Exception werfen könnte und dann array nicht freigegeben wird.

    Reine Mutmassung. Es hat erstmal kein Speicherleck, da keine Exception geworfen wird.



  • Anonymus42 schrieb:

    Hallo, bin am C++ lernen und lese häufig alle möglichen Threads hier, und mir ist aufgefallen, dass anstatt Arrays immer zu std::vector geraten wird. Wollte mir in meiner Lernphase als nächstes mal die Arrays anschauen, die ich auch aus Java etc. kenne, aber es wurde hier im Forum immer eher zu std::vector geraten.

    Die Arrays, die du aus Java kennst, gibt es in C++ nicht.

    Anonymus42 schrieb:

    - Welche Vor-/Nachteile hat std::vector und sollte man die "normalen" Arrays zuerst beherrschen, bevor man zu std::vector kommt?

    Hierzu könnte man mehrere Seiten schreiben.

    Anonymus42 schrieb:

    Was sind "normale Arrays"? Es gibt da mindestens zwei
    - Hat jemand eine gute Erklärung zur Funktionsweise von std::vector?

    Was sagt denn dein schlaues C++ Buch dazu?

    Anonymus42 schrieb:

    Mit "normale Arrays" meinte ich auch sowas wie

    int xyz[];
    int abc[3] = {1, 2, 3};
    

    .

    int[] ist kein vollständiger Typ. In Java wäre das eine Array-Referenz, in C++ gibt's sowas nicht. Und wenn du so etwas mal als Funktionsparametertyp siehst, dann ist das in Wirklichkeit int*, nicht int[]. Das ersetzt der Compiler in diesem Kontext einfach. Es ist also eigentlich egal, ob du int* oder int[] als Funktionsparametertyp schreibst. Allerdings könnte man damit dem Leser noch mitteilen, ob die Funktion nur auf ein Objekt zugreifen will, oder ggf auch auf mehrere, die hintereinander im Speicher liegen. So könnte man es als ein Teil der Funktions-"Dokumentation" ansehen.

    Das Array/Zeiger Thema wurde unendlich mal totdiskutiert. Bitte recherchiere das selbst, hol dir ein gutes Buch, schau in diverse FAQs rein. Danke.

    Übrigens: C++ ist eine komplett andere Sprache als Java. Versuche nicht einfach die Dinge, die du in Java schreiben würdest, nach C++ zu übertragen. Das ist genauso blöd wie Wort-für-Wort Übersetzungen von englischen Gedichten ins Deutsche. Da kommt einfach Murks bei raus.



  • Sone schrieb:

    , ich dachte std::vector ist sozusagen eine Ablösung für diesen normalen Array

    Nö, std::vector ist die "Ablösung" für new [] / delete [] .

    Imho ist das eher std::valarray oder eben dein heiß geliebtes dynarray, das es halt noch nicht im Standard gibt.
    std::vector ist ja mächtiger. (Obwohl der Name Anderes vermuten lässt, ein VeKtor bezeichnet ja eigentlich auch nur ein n-Tupel, genauso wie ein Array).



  • Ethon schrieb:

    Imho ist das eher std::valarray oder eben dein heiß geliebtes dynarray, das es halt noch nicht im Standard gibt.
    std::vector ist ja mächtiger.

    😕
    std::valarray is viel viel mächtiger als vector, der ist bloss ein dummes Array mit einer Hilfsfunktion, die ein neues Array allokieren kann und das alte rüberkopiert.



  • valeria schrieb:

    Ethon schrieb:

    Imho ist das eher std::valarray oder eben dein heiß geliebtes dynarray, das es halt noch nicht im Standard gibt.
    std::vector ist ja mächtiger.

    😕
    std::valarray is viel viel mächtiger als vector, der ist bloss ein dummes Array mit einer Hilfsfunktion, die ein neues Array allokieren kann und das alte rüberkopiert.

    Meinte nur um Bezug auf die Speicherung der Elemente. new[] kann nicht wachsen, std::vallarray auch nicht.
    Stimmt schon, std::dynarray ist eine Lücke, aber die kommt hoffentlich bald! (Auch wenn es mir eher um den dynamischen Stackspeicher als um die Vollständigkeit geht :p )


Anmelden zum Antworten