Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

eXpl0it3r

Treue Seele

  • »eXpl0it3r« ist der Autor dieses Themas

Beiträge: 386

Wohnort: Schweiz

Beruf: Professional Software Engineer

  • Private Nachricht senden

11

09.08.2012, 23:50

Das Problem mit den jagged Arrays ist zumindest weg, bzw., dass Zeilen theoretisch eine unterschiedliche Länge haben können.
Ja das Problem mit einem Jagged Array kommt ja nur vor wenn es dann auch wirklich gemacht wird, sprich nur weil die Möglichkeit besteht muss es noch lange nicht heissen, dass man es macht. Ausserdem spielt es keine Rolle wenn jetzt ein vector in einem vector länger ist oder nicht, da der "2D" vector ja sowieso schon fragmentiert ist. ;)

letztlich wäre das beste was dot gesagt hat..
dot hat viel gesagt, was meinst du jetzt? So in etwa wie ich es im zweiten Teil des Fazits gesagt habe?
Blog: https://dev.my-gate.net/
—————————————————————————
SFML: https://www.sfml-dev.org/
Thor: http://www.bromeon.ch/libraries/thor/
SFGUI: https://github.com/TankOs/SFGUI/

idontknow

unregistriert

12

09.08.2012, 23:58

Naja du hast schon Recht, dass es auf die Verwendung ankommt. Aber guter Code ist numal Code den man nicht falsch benutzen kann. Und bei 2 std::vectors kann man das nunmal und sogar sehr einfach. Natürlich ist das noch ein sehr einfaches Beispiel und ne falsche Handhabung wird da nicht wirklich vor kommen, aber trotzdem kann man es dann doch deutlich besser machen!!

Und ja, das was du im zweiten Teil deines Fazits gesagt hast. Wobei natürlich noch ne maximale Begrenzung schön wäre, denn letztlich ist die Array Größe ja fix. Also wäre eher ein statisches Array, dass mit einem dynamischen size Wert initialisiert wird optimal.

eXpl0it3r

Treue Seele

  • »eXpl0it3r« ist der Autor dieses Themas

Beiträge: 386

Wohnort: Schweiz

Beruf: Professional Software Engineer

  • Private Nachricht senden

13

10.08.2012, 00:12

Naja du hast schon Recht, dass es auf die Verwendung ankommt. Aber guter Code ist numal Code den man nicht falsch benutzen kann. Und bei 2 std::vectors kann man das nunmal und sogar sehr einfach.
Zja man kann eigentlich allen Code falsch benutzen, aber falls die grösse fix ist, wäre ein std::array ja vielleicht gar nicht so schlecht.

Und ja, das was du im zweiten Teil deines Fazits gesagt hast. Wobei natürlich noch ne maximale Begrenzung schön wäre, denn letztlich ist die Array Größe ja fix. Also wäre eher ein statisches Array, dass mit einem dynamischen size Wert initialisiert wird optimal.
Die verlangt natürlich manuelle Speicherverwaltung (new + delete), was wiederum sehr schnell zu unschönen Memory Leaks führen kann. Und wie schon oft wiederholt, sollte man new und delete in neuerem C++ Code praktisch nie mehr sehen. (Nach Herb Sutter) ;)
Blog: https://dev.my-gate.net/
—————————————————————————
SFML: https://www.sfml-dev.org/
Thor: http://www.bromeon.ch/libraries/thor/
SFGUI: https://github.com/TankOs/SFGUI/

idontknow

unregistriert

14

10.08.2012, 00:25

Naja du hast schon Recht, dass es auf die Verwendung ankommt. Aber guter Code ist numal Code den man nicht falsch benutzen kann. Und bei 2 std::vectors kann man das nunmal und sogar sehr einfach.
Zja man kann eigentlich allen Code falsch benutzen, aber falls die grösse fix ist, wäre ein std::array ja vielleicht gar nicht so schlecht.

Und ja, das was du im zweiten Teil deines Fazits gesagt hast. Wobei natürlich noch ne maximale Begrenzung schön wäre, denn letztlich ist die Array Größe ja fix. Also wäre eher ein statisches Array, dass mit einem dynamischen size Wert initialisiert wird optimal.
Die verlangt natürlich manuelle Speicherverwaltung (new + delete), was wiederum sehr schnell zu unschönen Memory Leaks führen kann. Und wie schon oft wiederholt, sollte man new und delete in neuerem C++ Code praktisch nie mehr sehen. (Nach Herb Sutter) ;)


Also natürlich kann man alles falsch benutzen. Der Witz ist, dass man die Möglichkeiten etwas falsch zu verwenden minimiert.
Und, dass man new und delete nie mehr sehen soll ist doch quatsch, immerhin braucht man das einfach für dynamische Speicherallokation. UNd wegen der Memory Leak Gefahr kann man einfach einen unique_ptr drauf packen und die Welt ist heile. Das mit den Memory Leaks is doch gar kein Problem mehr, gibt die Mittel das zu verhindern man muss sie nur benutzen. Das der ANastz so natürlich nicht geeignet ist für einen Anfänger ist klar.

PS: Ich wäre mal mit den ganzen Zitaten von C++ Größen vorsichtig.

eXpl0it3r

Treue Seele

  • »eXpl0it3r« ist der Autor dieses Themas

Beiträge: 386

Wohnort: Schweiz

Beruf: Professional Software Engineer

  • Private Nachricht senden

15

10.08.2012, 00:38

Also natürlich kann man alles falsch benutzen. Der Witz ist, dass man die Möglichkeiten etwas falsch zu verwenden minimiert.
Und, dass man new und delete nie mehr sehen soll ist doch quatsch, immerhin braucht man das einfach für dynamische Speicherallokation. UNd wegen der Memory Leak Gefahr kann man einfach einen unique_ptr drauf packen und die Welt ist heile. Das mit den Memory Leaks is doch gar kein Problem mehr, gibt die Mittel das zu verhindern man muss sie nur benutzen. Das der ANastz so natürlich nicht geeignet ist für einen Anfänger ist klar.

PS: Ich wäre mal mit den ganzen Zitaten von C++ Größen vorsichtig.
:dash: :dash: :dash:
Hey schau wir irgnorieren mal alles existierenden "managed" Container und machen da unser eigenes "unmanaged" Ding und dann wieder alles mit einem unique_ptr zu "fixen". Ach ja die Leute vom Standard Komitee haben ja keine Ahnung, hört bloss nicht auf die! :dash:

Viel Spass in deiner C99 Welt, ich nehme den C++11 Zug und verwende was empfohlen ist.

Und um es noch einmal klar zu machen, wenn du den "korrekten" Weg gehen willst, dann nimm ein 1D std::vector<T> oder ein std::array, wenn es aber nicht extremst zeitkritisch ist oder man alles optimiert haben will, nimm was immer du magst, solange es dir passt.
Blog: https://dev.my-gate.net/
—————————————————————————
SFML: https://www.sfml-dev.org/
Thor: http://www.bromeon.ch/libraries/thor/
SFGUI: https://github.com/TankOs/SFGUI/

idontknow

unregistriert

16

10.08.2012, 00:48

Ich glaub du hast nicht ganz verstanden was ich meine.

Weder tr1::array noch vector bieten für das Problem eine perfekte Lösung. Gesucht war ein 2 dimensionales Array für die Level. Ich bezweifle mal stark, dass es Sinn macht die Levelgröße irgendwie zu ändern. Allerdings kann es verschiedene Levelgrößen geben die dynamisch bestimmt werden. Deswegen wäre was man eigentlich haben wollte ein tr1::array mit einer dynamischen Startgröße, die später nicht mehr änderbar ist (weil es kein Sinn macht). Natürlich is das alles etwas übertrieben und theoretisch aber das is nunmal ne Diskussion über die beste Lösung.
Ich verstehe dein Problem nicht.

Und nur, damit wir das mal klarstellen, weil du ständig auf dem heiligen Standard und deinen Zitaten rumzitierst und darauf hinweist: Du hast hier 2 Zitate gebracht (werte das von Herb Sutter auch mal als Zitat) und du hast es beidesmal verbockt. (das ist jetzt nicht böhse gemeint man sollte nur aufpassen was und wie man zitiert..) Von wegen C99 Zug. Die STL bietet nunmal nur STANDARD Container und Algorithmen. Wenn mans eben perfekt auf die eigenen Bedürfnisse zugeschnitten haben will muss man es einfach selber machen, zumindest zum Teil, so einfach.

PS: Im Endeffekt hättest du in der Klasse im Prinzip ein statisches Array, dessen Größe sich nach dem initialisieren nie mehr ändert, ich will mal sehen wo der heilige Standard da schneller ist. NUr weil der Standard sehr gute Implementierungen hat, heißt das nicht dass man bei jeder Gelegenheit seine Lösung so umbiegen muss, dass man etwas aus der STL verwendet..

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »idontknow« (10.08.2012, 00:54)


eXpl0it3r

Treue Seele

  • »eXpl0it3r« ist der Autor dieses Themas

Beiträge: 386

Wohnort: Schweiz

Beruf: Professional Software Engineer

  • Private Nachricht senden

17

10.08.2012, 01:03

Ich glaub du hast nicht ganz verstanden was ich meine.

Weder tr1::array noch vector bieten für das Problem eine perfekte Lösung. Gesucht war ein 2 dimensionales Array für die Level. Ich bezweifle mal stark, dass es Sinn macht die Levelgröße irgendwie zu ändern. Allerdings kann es verschiedene Levelgrößen geben die dynamisch bestimmt werden. Deswegen wäre was man eigentlich haben wollte ein tr1::array mit einer dynamischen Startgröße, die später nicht mehr änderbar ist (weil es kein Sinn macht). Natürlich is das alles etwas übertrieben und theoretisch aber das is nunmal ne Diskussion über die beste Lösung.
Ich verstehe dein Problem nicht.
Du machst es ja oft auch nicht leicht zu verstehen was du meinst, wenn du z.B. Array sagst impliziert dies ein nativ Array und nicht ein std::array. Dieser neu formulierten Aussage stimme ich vollkommen zu.

Und nur, damit wir das mal klarstellen, weil du ständig auf dem heiligen Standard und deinen Zitaten rumzitierst und darauf hinweist: Du hast hier 2 Zitate gebracht (werte das von Herb Sutter auch mal als Zitat) und du hast es beidesmal verbockt.
Dann erklär mir wie ich die "verbockt" habe? :hmm:

Von wegen C99 Zug. Die STL bietet nunmal nur STANDARD Container und Algorithmen. Wenn mans eben perfekt auf die eigenen Bedürfnisse zugeschnitten haben will muss man es einfach selber machen, zumindest zum Teil, so einfach.
Ja es sind STANDARD Container und Algorithmen, aber sie sind auch GENERISCH und OPTIMIERT programmiert und den Compilern sehr gut bekannt, was zu weiteren Optimierungen führen kann.
Klar jedem steht es frei selbst Strukturen zu schreiben, aber wenn es nicht nötig ist, muss man es ja nicht machen und sobald die Komplexität solcher Strukturen etwas zu nimmt, würde ich behaupten, dass eine Lösung mit standard Containern optimaler läuft. ;)

PS: Im Endeffekt hättest du in der Klasse im Prinzip ein statisches Array, dessen Größe sich nach dem initialisieren nie mehr ändert, ich will mal sehen wo der heilige Standard da schneller ist. NUr weil der Standard sehr gute Implementierungen hat, heißt das nicht dass man bei jeder Gelegenheit seine Lösung so umbiegen muss, dass man etwas aus der STL verwendet..
In welcher Klasse? Und meinst du jetzt wieder std::array oder ein nativ Array?

Ich sehe nicht wo dein Problem mit dem Standard ist, ohne ihn gäbe es kein klar definiertes C++ und auch keine optimierten Container, aber das brauchst du ja anscheinend nicht, da deine eigenen Strukturen alle super schön und optimal sind. :P
Blog: https://dev.my-gate.net/
—————————————————————————
SFML: https://www.sfml-dev.org/
Thor: http://www.bromeon.ch/libraries/thor/
SFGUI: https://github.com/TankOs/SFGUI/

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »eXpl0it3r« (10.08.2012, 01:09)


idontknow

unregistriert

18

10.08.2012, 01:13

Okey ich gebe zu ich habe implizit an tr1:.array gedacht nicht an ein natives. my bad. Natürlich sind die standard Container sehr gut. Aber wenn man eben eine Lösung haben will die perfekt auf das Problem zugeschnitten ist das man hat kommt man mit den Containern eben nicht immer zu einem Ergebnis. Da muss man dann Kompromisse eingehen oder es selber machen.

Ich meinte die hypothetische levelklasse. Der würde man als Parameter die Leveldimensionen übergeben und die Klasse würde ein entsprechendes natives Array allokieren, allerdings muesste man dann alle Zugriffsoperationen neu schreiben um Zugriffsverletzungen abzufangen. ABer ich bin mir sicher es gibt sowas wie tr1::array mit der Möglichkeit einen dynamischen Größenwert ans Array zu übergeben und entsprechenden Zugriffsoperationen bestimmt schon irgendwo in den Weiten des Internets :).

Was die Zitate angeht: Normale 2D Arrays sind sicherlich nicht fragmentiert du hast da irgendwie den standard falsch interpretiert ich glaube dot wollte da noch was dazu schreiben, ich will das nicht genauer ausführen weil ich mir nicht zutraue den standard 100%ig richtig zu verstehen und das lieber Leuten überlasse die das können. Auf jedenfall stimmt die Aussage, über die Fragmentierung so nicht.
Was das herb Sutter Zitat angeht mit keinem new + delete. Soweit ich weiß (beziehe mich jetzt auf seinen Blog bzw seine Website) hat er nur gesagt es sollte nirgendwo ein delete sein. Aber er hat bestimmt nicht gesagt man soll kein new + delete mehr haben. Seine Kernaussage ist, dass man ownerships von dynamischen Speicherbereichen also welche die mit new allokiert wurden immer an smart Pointer übergeben soll (und damit das delete wegfällt). Das ist aber was ganz andere als, es soll in C++ Code kein new + delete mehr geben.

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

19

10.08.2012, 01:13

Nun kommt aber das grosse ABER, der einzige Grund warum, dass ein "2D" vector schlecht ist, ist das Memory Layout, was natürlich zu einer etwas schlechteren Performance führt.

Nein, das ist nicht der einzige Grund. Das ist ein Grund. Ein sehr viel wichtigerer Grund ist, dass ein jagged Array sich strukturell fundamental von einem normalen rechteckigen Array unterscheidet, da jede Zeile unterschiedliche Länge haben kann, was ich aber eben nicht haben will. Im konkreten Fall wollen wir ein rechteckiges Array. Ein std::vector<std::vector<T>> drückt aber etwas ganz anderes aus. In weiterer Folge entstehen dann genau die Probleme, die Nathax anfangs hatte. Da es mit unserem std::vector<std::vector<T>> unmöglich ist, den Constraint "rechteckig" explizit auszudrücken, muss nun sämtlicher Code, der mit dem std::vector<std::vector<T>> arbeitet, diese implizite Annahme berücksichtigen. Ich muss beispielsweise bei der Initialisierung des vectors daran denken, jeder Zeile die richtige Anzahl an Elementen zu geben, da der ganze Rest des Programms davon abhängt. Nichts hindert mich aber daran, jeder Zeile eine andere Länge zu geben, es gibt keinen Weg diese Anforderung über einen std::vector<std::vector<T>> statisch zu forcieren.
Bessere Lösung: 5 min. investieren und einen eigenen Datentyp für ein zweidimensionales rechteckiges Array auf Basis eines einfachen std::vector definieren, der eben die (triviale) Indexberechnung kapselt. Selbst wenn ich, aus welchen Gründen auch immer (z.B. für eine riesige dünn besetzte Matrix) oder von mir aus auch nur der Einfachheit halber, in der Implementierung dieses Datentyps einen std::vector<std::vector<T>> benutze, ist das schon tausendmal besser. Der entscheidende Punkt bleibt, dass das logische Konzept eines rechteckigen Arrays nicht dem Konzept eines std::vector<std::vector<T>> entspricht. std::vector<std::vector<T>> ist für unser Problem das falsche Interface. Es gibt durchaus Fälle, wo ein std::vector<std::vector<T>> genau das ist, was ich haben will, der hier ist nur eben keiner. Wenn der Threadersteller überhaupt nur ein Array statischer Größe haben will, wäre ein stinknormales sf::Color[40][11] übrigens wohl die beste Lösung.

Es mag wohl nun gut sein sich selbst Prinzipien anzueignen, welche solche nicht optimalen Strukturen verhindert, jedoch zum Preis von etwas mehr Programmieraufwand und möglichen Fehlernquellen, jedoch ist es keine Hilfe für Anfänger solche Optimierungsprinzipien bei bringen zu wollen.

Im Gegenteil, das Jagged Array ist eben eine mögliche Fehlerquelle, da es nicht das ausdrückt, was ich eigentlich ausdrücken will und als Folge davon implizite Annahmen über mein ganzes Programm verteilt berücksichtigt werden müssen. Genau das versuche ich hier schon die längste Zeit bewusst zu machen. Ich seh aber, dass ich mich da besser hätte ausdrücken können.

Noch zwei weiter Punkte, der Gewinn durch das Verwenden von einem 1D Array/Vector ist meist sehr minimal vorallem im Vergleich zum zusätzlichen Aufwand den man hat, da man selten mit 10'000 von Elementen zu tun hat. Obwohl ich deinen Code (Art) nicht kenne, so wage ich trotzdem zu behaupten, dass du an anderen Stellen viel schlimmere schlecht performante Operationen durchführst und sich somit der ganze Aufwand eigentlich gar nicht gross lohnt. (Das ist nur eine Behaupt basierend auf der Tatsache, dass es keinen "perfekten" Code gibt.) ;)

Nochmal: Es geht mir in diesem Fall überhaupt nicht um die Performance, es geht einzig und allein darum, dass ein jagged Array hier nicht das ist, was wir haben wollen.

Zja der Standard sagt aber etwas anderes über mehrdimensionale Arrays:

Zitat von »ISO/IEC 14882-2011 § 8.3.4-7«

A consistent rule is followed for multidimensional arrays. If E is an n-dimensional array of rank i×j ×. . .×k, then E appearing in an expression that is subject to the array-to-pointer conversion (4.2) is converted to a pointer to an (n−1)-dimensional array with rank j ×. . .×k. If the * operator, either explicitly or implicitly as a result of subscripting, is applied to this pointer, the result is the pointed-to (n − 1)-dimensional array, which itself is immediately converted into a pointer.
Das heisst somit, dass ein zweidimentionales Array (Bsp. int a[10][10];) ebenfalls einen fragmentierten Speicherbereich aufweist.

Nope, dieser Absatz sagt nichts dergleichen. Er fasst lediglich die für Arrays wesentlichen Konsequenzen von § 4.2-1 (Array-to-pointer conversion), § 5.2.1-1 (Subscripting) und § 5.3.1-1 (Indirection) zusammen und ist damit eigentlich sogar redundant. Grund für deine Verwirrung ist wohl, dass du das entscheidende "is converted to a pointer" (was, wie bereits gesagt, nur eine Wiederholung von § 4.2-1 ist) als "is a pointer" interpretierst, was aber eben genau nicht dort steht. Der eigentliche Schlüssel liegt hier:

Zitat von »ISO/IEC 14882-2011 § 8.3.4-1«

An object of array type contains a contiguously allocated non-empty set of N subobjects of type T.

Da ein n-dimensionales Array einem Array aus Arrays der Dimension n-1 entspricht (unter anderem § 8.3.4-2), folgt rekursiv, dass ein n-dimensionales Array ein zusammenhängender Speicherbereich ist. (Siehe dazu auch Beispiel 8.3.4-8 und Anmerkung 8.3.4-9)
Ich muss aber zugeben, dass mir diese Definition von Arrays auch lange Zeit widersprüchlich erschien. ;)

Für maximale Performance ist es empfohlen std::vector<T> oder T[x][y] zu verwenden, wobei hier angemerkt werden sollte, dass std::vector<T> keinerlei Nachteilen über einem nativ Array haben und sogar in Verbindung mit Iteratoren schneller sein können (entweder hier oder hier erwähnt), ausserdem bietet std::vector<T> weiter Funktionalitäten an und das komplette manualle Speichermanagment entfällt.

Auch nicht ganz richtig. Im Gegensatz zu einem std::vector<T>, kann ich ein normales Array z.B. auf dem Stack anlegen, während der std::vector<T> seinen Speicher auf dem Heap (und damit schonmal wesentlich langsamer) allokiert. Abgesehen davon, spar ich mit dem Array potentiell eine Indirektion (zugegeben, das ist wohl tatsächlich praktisch immer völlig irrelevant). Überhaupt ist ein T[x][y] rein prinzipiell was völlig anderes als ein std::vector (statische vs. dynamische Größe). Auch sei darauf hingewiesen, dass ich mich bei einem T[x][y] niemals um Speicherverwaltung kümmern muss (ein mehrdimensionales Array kann gar nicht dynamisch erzeugt werden).
Würde mich außerdem sehr interessieren, wo genau du all das in diesen beiden Talks so gehört haben willst, denn ich kann mich grad nur an den Vergleich von std::vector vs. std::list aus der Keynote erinnern...

Dieser Beitrag wurde bereits 14 mal editiert, zuletzt von »dot« (10.08.2012, 03:02)


eXpl0it3r

Treue Seele

  • »eXpl0it3r« ist der Autor dieses Themas

Beiträge: 386

Wohnort: Schweiz

Beruf: Professional Software Engineer

  • Private Nachricht senden

20

10.08.2012, 03:34

Was die Zitate angeht: Normale 2D Arrays sind sicherlich nicht fragmentiert du hast da irgendwie den standard falsch interpretiert ich glaube dot wollte da noch was dazu schreiben, ich will das nicht genauer ausführen weil ich mir nicht zutraue den standard 100%ig richtig zu verstehen und das lieber Leuten überlasse die das können. Auf jedenfall stimmt die Aussage, über die Fragmentierung so nicht.
Ja das ging da schief, ich hab die Passage falsch verstanden, n-d Arrays sind nicht fragmentiert.
Was das herb Sutter Zitat angeht mit keinem new + delete. Soweit ich weiß (beziehe mich jetzt auf seinen Blog bzw seine Website) hat er nur gesagt es sollte nirgendwo ein delete sein. Aber er hat bestimmt nicht gesagt man soll kein new + delete mehr haben. Seine Kernaussage ist, dass man ownerships von dynamischen Speicherbereichen also welche die mit new allokiert wurden immer an smart Pointer übergeben soll (und damit das delete wegfällt). Das ist aber was ganz andere als, es soll in C++ Code kein new + delete mehr geben.
Er sagte aber auch, dass man immer std::make_shared und std::make_unique verwenden soll und somit entfällt das new auch. Klar geht es hier um Ownership.

Nein, das ist nicht der einzige Grund. Das ist ein Grund. Ein sehr viel wichtigerer Grund ist, dass ein jagged Array sich strukturell fundamental von einem normalen rechteckigen Array unterscheidet, da jede Zeile unterschiedliche Länge haben kann, was ich aber eben nicht haben will. Im konkreten Fall wollen wir ein rechteckiges Array. Ein std::vector<std::vector<T>> drückt aber etwas ganz anderes aus. In weiterer Folge entstehen dann genau die Probleme, die Nathax anfangs hatte. Da es mit dem std::vector<std::vector<T>> unmöglich ist, den Constraint "rechteckig" explizit auszudrücken, muss nun sämtlicher Code, der mit dem std::vector<std::vector<T>> arbeitet, diese implizite Annahme berücksichtigen. Ich muss beispielsweise bei der Initialisierung des vectors daran denken, jeder Zeile die richtige Anzahl an Elementen zu geben, da der ganze Rest des Programms davon abhängt. Nichts hindert mich aber daran, jeder Zeile eine andere Länge zu geben, es gibt keinen Weg diese Anforderung über einen std::vector<std::vector<T>> statisch zu forcieren.
Bessere Lösung: 5 min. investieren und einen eigenen Datentyp für ein zweidimensionales rechteckiges Array auf Basis eines einfachen std::vector definieren, der eben die (triviale) Indexberechnung kapselt. Selbst wenn ich, aus welchen Gründen auch immer (z.B. für eine riesige dünn besetzte Matrix) oder von mir aus auch nur der Einfachheit halber, in der Implementierung dieses Datentyps einen std::vector<std::vector<T>> benutze, ist das schon tausendmal besser. Der entscheidende Punkt bleibt, dass das logische Konzept eines rechteckigen Arrays nicht dem Konzept eines std::vector<std::vector<T>> entspricht. std::vector<std::vector<T>> ist für unser Problem das falsche Interface. Es gibt durchaus Fälle, wo ein std::vector<std::vector<T>> genau das ist, was ich haben will, hier ist das aber eben nicht der Fall.
Jetzt verstehe ich, dir ging es immer nur darum, dass es rein theoretisch möglich ist die Länge zu verändern und man es darum nicht verwenden soll.

Wenn der Threadersteller überhaupt nur ein Array statischer Größe haben will, wäre ein stinknormales sf::Color[40][11] übrigens wohl die beste Lösung.
Bis auf dass er sich selbst die grösser merken muss (schlechtes Design, Eigenschaften eines 'Objekts' werden ausserhalb gelagert) und auch viel mehr aufpassen muss mit den Indizes.

Da ein n-dimensionales Array einem Array aus Arrays der Dimension n-1 entspricht (siehe auch § 8.3.4-2), folgt rekursiv, dass ein n-dimensionales Array ein zusammenhängender Speicherbereich ist.
Ja das hatte ich falsch gelesen.

Wieder nicht ganz richtig. Im Gegensatz zu seinem std::vector<T> kann ich ein normales Array z.B. auf dem Stack anlegen, während der std::vector<T> auf dem Heap (und damit schonmal wesentlich langsamer) allokiert wird. Abgesehen davon spar ich mir dem Array potentiell eine Indirektion (zugegeben, das ist wohl praktisch immer völlig irrelevant). Überhaupt ist ein T[x][y] rein prinzipiell was völlig anderes als ein std::vector (statische vs. dynamische Größe). Auch sei darauf hingewiesen, dass ich mich bei einem T[x][y] niemals um Speicherverwaltung kümmern muss.
Naja auch nicht ganz richtig vector Mechanismen werden sehr wohl auf dem Stack gespeichert, nur die Daten halt nicht, doch ich denke es macht hier nun wirklich bald mal keinen Sinn mehr zu diskutieren was nun schneller ist, denn am Ende wird das Ganze dann doch vom OS entschieden und wer weiss wie dieses sich in allen Fällen und unter allen möglichen Umständen verhält. ;)
Interessante Anmerkung noch: Wenn der Speicher eines vectors bei der Initialisierung alles auf einmal alloziert wird, so wird der Speicherbereich in den meisten Fällen ebenfalls kontinuierlich sein. Klar dies ist nicht garantiert aber es zeigt halt, wieso es in den meisten Fällen nicht sehr tragisch ist 2D vectoren zu verwenden, auch wenn sie halt die Möglichkeit bieten sich selbst zu vergrössern/verkleinern und dies nicht direkt gewollt ist.

Hier ein kleines Beispiel, der erste Part zeigt was man alles komische mit der Array Definition im Standard anstellen kann und zeigt gleichzeitig, dass der Speicher fortlaufend ist und der zweite Teil gibt die Adressen eines vectors aus, womit man sieht, dass dieser Speicher ebenfalls kontinuerlich alloziert wird (aber nicht garantiert ist!). :)

Würde mich außerdem sehr interessieren, wo genau du das in diesen beiden Talks so gehört haben willst, denn ich kann mich grad nur an den Vergleich von std::vector vs. std::list aus der Keynote erinnern...
Ich müsste das noch einmal anschauen, evtl. habe ich das auch noch falsch im Kopf, oder Herb Sutter sagte das in einem anderen Vortrag über Lambda-Funktionen.
Blog: https://dev.my-gate.net/
—————————————————————————
SFML: https://www.sfml-dev.org/
Thor: http://www.bromeon.ch/libraries/thor/
SFGUI: https://github.com/TankOs/SFGUI/

Werbeanzeige