C++ std::vector an glibc Funktionen übergeben

Vom einfachen Programm zum fertigen Debian-Paket, Fragen rund um Programmiersprachen, Scripting und Lizenzierung.
Antworten
owl102

Re: C++ std::vector an glibc Funktionen übergeben

Beitrag von owl102 » 12.12.2018 17:54:00

JTH hat geschrieben: ↑ zum Beitrag ↑
11.12.2018 20:40:11
Die Lösung find ich völlig okay so. C++ und seine Bibliothek versucht dir (vereinfachende) Abstraktionen anzubieten, wie std::vector::push_back() und den Großteil der restlichen vector-Schnittstelle.
Die Lösung von MSfree finde ich nicht ok. Wenn man die Größe weiß, ist es IMHO sträflich bei einem std::vector mit push_back() zu arbeiten. Wenn schon umkopieren, dann resize() + Array-Zugriff (oder std::copy()), ansonsten wird std::vector intern x-mal den Speicher neu anfordern/freigeben und umkopieren, weil das Array ja dynamisch immer größer wird.

Der Argumentation "Nunja, wenn du wüßtest, wie oft Daten in "moderner" Software im Hauptspeicher hin und her kopiert werden, würde dir sofort schlecht werden." mag ich auch nicht folgen. Wenn man schon weiß, wie es mit weniger umkopieren geht, sollte man das schon auch so machen.

alexander_ro
Beiträge: 298
Registriert: 16.01.2006 17:44:21
Lizenz eigener Beiträge: GNU General Public License

Re: C++ std::vector an glibc Funktionen übergeben

Beitrag von alexander_ro » 12.12.2018 18:18:26

JTH meinte da meine Lösung: den Pointer auf die Daten in dem vector an die read Funktion zu übergeben. Bevor man das aber tut muss man mit resize dem vector auf eine passende Speicher größe bringen. Sollte read aber wegen erreichen des EOF eine kleiner Menge an Byte lesen muss man mit einem zweiten resize den vector auf die wirkliche größe verkleinern.

Bisher hat sich keine bessere Lösung für das Problem gefunden.

Das in vielen Software Projekten oft nur Daten kopiert werden weil den anderen Teil eine andere Abteilung macht stimmt schon. Rechenzeit zu verschwenden ist leider Modern. Green IT endet immer bei der Hardware das Software auch Strom verschwenden kann ist noch nicht in viele Experten Köpfe vorgedrungen.

Benutzeravatar
bmario
Beiträge: 1256
Registriert: 05.09.2007 12:15:47
Lizenz eigener Beiträge: MIT Lizenz
Wohnort: Dresden

Re: C++ std::vector an glibc Funktionen übergeben

Beitrag von bmario » 13.12.2018 09:18:51

Ich antworte direkt mal auf den OP, hier kam ja teilweise echt komische sSachen. 8O
alexander_ro hat geschrieben: ↑ zum Beitrag ↑
11.12.2018 11:11:13
Ich suche jetzt nach einer Möglichkeit die Daten effizient in einen C++ Container zu bekommen. Der std::vector würde sich dafür gut eignen ich habe da ein Beispiel im Netz gefunden das aber meiner Meinung nicht ganz richtig ist. Das sah so aus:

Code: Alles auswählen

std::vector Puffer;
read (iIntDevFile, &Puffer[0], iLaenge);
Wenn man aber bei einem vector den Pointer benutzt wird doch kein Speicher für die zu speichernden Daten reserviert.
Du hast recht, so wird kein Speicher allokiert und der vector nicht auf die richtige Größe gesetzt. Das hat aber mit dem Pointer nichts zu tun. Diese Notation hat man vor C++11 benutzt, da gab es schlich die data() Memberfunktion noch nicht.

alexander_ro hat geschrieben: ↑ zum Beitrag ↑
11.12.2018 11:11:13
Meine Lösung jetzt sieht etwas anders aus Funktioniert aber leider auch nicht ganz richtig:

Code: Alles auswählen

std::vector<char> vecDaten;
vecDaten.reserve (2);
read (iIntDevFile, vecDaten.data (), 2);
So hat man zwar die zwei Byte tatsächlich dann im vector gespeichert. Leider liefert die Funktion:
Wie die anderen schon angemerkt hatten, fehlt hier nur noch das resize() des vectors.

Code: Alles auswählen

std::vector<char> vecDaten;
vecDaten.reserve (2);
auto size = read (iIntDevFile, vecDaten.data (), 2);
vecDateb.resize(size);
Aber, wie es halt immer ist, der Teufel steckt halt im Detail. Der erste Satz in der manpage von read() lautet:
read() attempts to read up to count bytes
Das heißt, mal abgesehehn vom einen echt Fehlerfall, kann read() auch jederzeit abbrechen bevor alle Daten aus der Datei gelesen wurden, oder bevor die Anzahl an angefragten Bytes gelesen wurden. Außerdem würde man aus Effizienzgründen nicht nur zwei Bytes lesen wollen.

Eine richtige Lösung würde mittels reserve() einen hinreichend großen Puffer anlegen, read() in einer Schleife ausführen und den Rückgabewert überprüfen. Sind alle Daten gelesen wurden oder EOF erreicht, kann die Schleife verlassen werden. Womöglich hat man nun zuviele Bytes gelesen, nicht nur dass man dann den vector wieder verkleinern muss, hat man zusätzlich das Problem, was tun mit den angefangenen Bytes vom nächsten logischen Lesevorgang? Im Fehlerfall sollte man damit auch umgehen. Und dann werden aus den zwei Zeilen Code ganz schnell 200 und man fragt sich, ob ioctl diese ganzen Mühen wert war. :wink:
Nichts zu tun ist viel besser,
als mit viel Mühe nichts zu schaffen. - Laotse

JTH
Moderator
Beiträge: 3014
Registriert: 13.08.2008 17:01:41
Wohnort: Berlin

Re: C++ std::vector an glibc Funktionen übergeben

Beitrag von JTH » 13.12.2018 10:40:00

bmario hat geschrieben: ↑ zum Beitrag ↑
13.12.2018 09:18:51
Wie die anderen schon angemerkt hatten, fehlt hier nur noch das resize() des vectors.

Code: Alles auswählen

std::vector<char> vecDaten;
vecDaten.reserve (2);
auto size = read (iIntDevFile, vecDaten.data (), 2);
vecDateb.resize(size);
Auf den zugrundeliegenden Speicher zuzugreifen, wenn die Größe noch 0 ist, ist allerdings nicht korrekt. std::vector::data() darf in dem Fall z.B. einen nullptr zurückgeben [1]. libstdc++ scheint das auch so zu machen [2] [3]. Das muss schon zweimal resize() sein.

[1] https://en.cppreference.com/w/cpp/conta ... data#Notes
[2] https://github.com/gcc-mirror/gcc/blob/ ... or.h#L1129
[3] https://github.com/gcc-mirror/gcc/blob/ ... or.h#L1810
Manchmal bekannt als Just (another) Terminal Hacker.

alexander_ro
Beiträge: 298
Registriert: 16.01.2006 17:44:21
Lizenz eigener Beiträge: GNU General Public License

Re: C++ std::vector an glibc Funktionen übergeben

Beitrag von alexander_ro » 13.12.2018 11:26:08

@bmario:
Ich konnte hier nichts komisches erkennen. Das einzige was nicht ging ist mit dem FILE von dem fdopen einen Stream zu erzeugen.

Das der Pointer auch richtig ist &Puffer[0] ist mir bekannt das hatte ich auch nicht gemeint und steht da auch nicht. In dem gefundenen Beispiel fehlt aber der physische Speicher. Meiner Meinung nach ist damit das Beispiel nicht ganz richtig und das steht da auch. Da es nun aber data () gibt macht es Sinn das zu verwenden.

Das read nicht nur so viele Byte lesen kann wie da sind oder auch wegen anderer Probleme abbrechen kann ist schon klar. Deshalb hatte ich ja gefragt wie man dem vector die Tatsächliche Größe geben kann. Das was aber der read jetzt direkt mit den ioctl zu tun hat weiß ich nicht so genau. Ich brauche die ioctl um die Hardware zu Programmieren um dann mit read die Messdaten zu lesen. Da ein Wert nur zwei Byte groß ist macht es keinen Sinn mehr Daten zu lesen. Klar könnte man das wenn man 1000 Byte liest bekommt man halt 500 mal den gleichen Wert. Daher brauche ich hier auch keine Schleife zum lesen das was Du beschreibst ist dann nötig wenn man große Datenmengen liest z.B. von einer Kamera oder aus Dateien.

Das resize die Daten nicht kaputt macht hatte vorher bei meiner Suche irgendwie übersehen. Aber ganz optimal ist die Lösung trotzdem nicht. Da resize ja wirklich den Speicher im vector kleiner macht und nicht nur merkt wo das letzte Byte mit echten Daten ist. Wenn man mit read in einer Schleife wie von Dir beschrieben Blöcke lesen will muss ich nach jedem lese Vorgang in dem der Puffer nicht voll war diesen neu erzeugen. Seltsam ist das man ja mit reserve Speicher reservieren kann und den dann Füllen. Macht man das über die vector Methoden kann reservierter Speicher und echter Inhalt unterschiedlich groß sein. Wenn man das über den Pointer macht kann man nur den vector physisch auf den vorhandenen Inhalt verkleinern und muss Speicher den man später vielleicht noch braucht freigeben. Deshalb kam mir die Lösung mit resize irgendwie nicht richtig vor. Aber wenn es nicht anders geht mach ich es halt mit zweimal resize. Sieht für mich als Übergang zu einem C++ Programm immer noch besser aus als ein char Array nochmal in was anderes um zu kopieren.

@JTH: Das resize einen nullptr zurückgibt wenn der vector keinen Speicher reserviert hat macht Sinn. Üblicherweise benutzt man den nullptr ja um ungültige Pointer zu Markieren.

Bei reserve macht der da nichts oder hab ich nur nicht die richtige stelle gefunden:
https://github.com/gcc-mirror/gcc/blob/ ... tor.h#L989

Antworten