Kopieren zwischen STL Container und 2D C Array
-
Hallo,
ich rufe eine C-API auf, die als Input ein Array "float array[ROWS][COLS]" erwartet. Der Input steht für eine Tabelle, jede Zeile für einen DataRecord. Im aufrufenden Code soll dafür ein STL-Container verwendet werden (bspw. vector<DataRecord> oder vector<vector<float>>). Der Inhalt des Containers soll in das C-Array kopiert werden, da die C-API den Buffer als In/Out Variable nutzt und überschreibt.
Wie kopiert man - möglichst elegant - einen 2D STL Container in ein 2D C Array?
-
@MartinX sagte in Kopieren zwischen STL Container und 2D C Array:
Wie kopiert man - möglichst elegant - einen 2D STL Container in ein 2D C Array?
Gar nicht, denn es gibt keine 2D STL Container.
-
Im allgemeinen ist ein vector<vector> rein logisch nicht auf ein 2D-Array übertragbar, schließlich könnte jede Zeile eine andere Länge haben. Wenn du der Meinung bist, dass das bei dir trotzdem immer geht, weil die Zeilen immer gleich lang sind, dann stellt sich die Frage, wieso das dann nicht ein vector<array> ist (wenn Zeilenlänge statisch), oder ein großer 1D-vector mit ein bisschen Zeilen/Spaltenlogik (wenn Zeilenlänge dynamisch). Das wäre nicht nur allgemeint effizienter, weil man nicht unnötig für die ungenutzte vector<vector>-Komplexität bezahlt, sondern würde auch dein Problem direkt lösen, denn es wäre gar keine Kopie nötig: Du könntest den data-Teil eines vector<array> bzw. eines großen 1D-vectors direkt wie ein C-Array benutzen, inklusive Übergabe an eine C-API, ohne irgendetwas aktiv kopieren zu müssen.
Das oben ist die richtige Lösung, die ich dringend empfehle. Korrekte Datenmodellierung ist wichtig. Was du beschreibst stinkt nach falschem Datenmodell.
Aber was ist, wenn man unbedingt einen vector<vector> in ein 2D-Array konvertieren muss? Erst einmal muss man, wie schon gesagt, ganz ganz sicher sein, dass die logische Voraussetzung auch wirklich gegeben ist, und alle Zeilen gleich lang sind. Danach ist, wie auch schon gesagt, ein vector<array> bzw. ein großer 1D-vector äquivalent zu einem 2D-C-Array. Das heißt, man besorgt sich einen passend großen Vector. Und in den kopiert man nun die einzelnen Untervectoren des Originals hinein, einen nach dem anderen, z.B. mit
std::copy
. Dabei natürlich immer um eine Zeilenlänge versetzt, also den ersten Subvector nach 0 bis N-1 (wenn N die Zeilenlänge ist), den zweiten nach N bis 2N-1 und so weiter. Und das data von diesem Vector gibst du dann an deine Funktion.Die zweite Methode nur in Notfällen nutzen, da muss wirklich jedes Element aktiv kopiert werden. Totale Verschwendung und wäre mit korrekter Modellierung nicht nötig.
Bei deinem vector<DataRecord> ist halt die Frage, was ein DataRecord intern ist. Wenn das eine POD-artige Ansammlung von floats ist, dann hast du ja quasi schon so etwas wie eine vector<array> unter anderem Namen, und bist fertig. Wenn das irgendein komplexer Datentyp ist, der intern z.B. einen eigenen Vector hat, dann hast du einen verkappten vector<vector> und solltest darüber nachdenken, ob das überhaupt so richtig modelliert ist.
-
@SeppJ sagte in Kopieren zwischen STL Container und 2D C Array:
Im allgemeinen ist ein vector<vector> rein logisch nicht auf ein 2D-Array übertragbar, schließlich könnte jede Zeile eine andere Länge haben. Wenn du der Meinung bist, dass das bei dir trotzdem immer geht, weil die Zeilen immer gleich lang sind, dann stellt sich die Frage, wieso das dann nicht ein vector<array> ist (wenn Zeilenlänge statisch), oder ein großer 1D-vector mit ein bisschen Zeilen/Spaltenlogik (wenn Zeilenlänge dynamisch). Das wäre nicht nur allgemeint effizienter, weil man nicht unnötig für die ungenutzte vector<vector>-Komplexität bezahlt, sondern würde auch dein Problem direkt lösen, denn es wäre gar keine Kopie nötig: Du könntest den data-Teil eines vector<array> bzw. eines großen 1D-vectors direkt wie ein C-Array benutzen, inklusive Übergabe an eine C-API, ohne irgendetwas aktiv kopieren zu müssen.
Ja, du hast Recht. Tatsächlich ist es eher ein array<array<T>> mit fixer Zeilen- und Spaltendimension. Ist das Memory-Layout von array<array<T, COLS>, ROWS> denn identisch zu T x[ROWS][COLS]?
-
Ja. Sogar das Layout von
vector<array<T, COLS>>::data()
ist identisch zu einemT[ROWS][COLS]
.Nur bei der auch erwähnten Möglichkeit, einen großen 1D-Vector zu nehmen und selber die Indizes zu berechnen, musst du halt aufpassen, dass du die Indizes in row-major Ordnung berechnest. Sprich: So wie die meisten Leute es sowieso intuitiv tun würden:
index_1d = row_index * col_length + col_index
. Wenn man das tut, ist auch das layout-kompatibel zu einemT[row_length][col_length]
.