Gentle(wo)man,
beim C++ üben habe ich die Macht der Ableitung erfahren. Jetzt versuche
ich gerade eine Klasse für Dateien zu schreiben. Da dachte ich, ich
leite einfach von std::FILE ab.
1
2
#include<cstdio>
3
#include<string>
4
5
usingnamespacestd;
6
7
classDatei:publicFILE{
8
public:
9
~Datei(){
10
fclose(this);
11
}
12
Datei(strings){
13
*this=*static_cast<Datei*>(fopen(s.c_str(),"w"));
14
}
15
};
16
17
intmain(){
18
Dateid("hallo.txt");
19
fprintf(&d,"Hallo Welt!");
20
return0;
21
}
Leider bekomme ich zur Laufzeit einen Fehler (nur mit GNU C++)
1
Fatal error: glibc detected an invalid stdio handle
Mit OpenWatcom 1.9 compiliert wird die Datei zwar ohne Fehlermeldung
erstellt, bleibt aber leer.
Wie gehe ich das richtig an, so dass ich mit einer von std::FILE
abgeleiteten Klasse arbeiten kann, bzw. wie initialisiert man das ganze?
glibc will dir sagen, dass du einen Pointer auf eine FILE-Instanz an die
stdio-Funktionen übergeben hast, die nicht von der glibc erzeugt wurde.
std::FILE ist keine richtige C++-Klasse, sondern nur ein zusätzlicher
Name für die normale FILE-struct aus der stdio.h von C. Davon eine
Klasse abzuleiten mag zwar zufälligerweise gehen, ist aber
typischerweise nicht sinnvoll.
Du kannst eine FILE-Struktur nicht einfach kopieren und hoffen, dass
fprintf, fclose usw. auch auf dieser Kopie funktionieren. In der
Standardbibliothek wird über die offenen Dateien Buch geführt, wobei
jede dieser Dateien wohl durch einen FILE-Pointer in eine Tabelle
repräsentiert ist. Ein Pointer auf dein Datei-Objekt kann darin aber
nicht enthalten sein, da es sich bei diesem Objekt ja nur um eine Kopie
handelt, von der die Standardbibliothek nichts weiß.
Generell sollte auf die Inhalte der FILE-Struktur nicht direkt, sondern
nur über die f*-Funktionen der Standardbibliothek zugegriffen werden.
C streams are objects of type std::FILE that can only be accessed and manipulated through pointers of type std::FILE* (Note: while it may be possible to create a local object of type std::FILE by dereferencing and copying a valid std::FILE*, using the address of such copy in the I/O functions is undefined behavior). Each C stream is associated with an external physical device (file, standard input stream, printer, serial port, etc).
Dein RAII-Ansatz ist im Prinzip richtig, allerdings kannst Du das eben
nicht mit Vererbung umsetzen, sondern mit Komposition.
Der FILE* Pointer ist ja nur ein Ressource-Handle, deswegen muss man
überlegen, was Du für eine Semantik haben möchtest, wenn Du
Datei-Objekte kopierst. Am besten machst Du die Klasse nur
vertausch-/verschiedbbar, aber nicht kopierbar (analog zu
std::ofstream).
In the Dessert I can't remember my Name schrieb:> Dirk K. schrieb:>> ein gutes Buch über C++ würde dir auch helfen>> Danke für Dein schonungsloses Feedback. Welches Buch kannst Du> empfehlen?
Hier ist eine Liste:
https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list/388282#388282
Mein Tipp: Den Stroustrup nicht als Anfänger lesen,
das ist harter Tobak. Nimm "C++ Primer" für den Einstieg.
Weiterführend Nicolai Josuttis (erklärt STL) und
Scott Meyers (für best practices).
Ich empfehle dir auch, C und C++ weitestgehend zu
trennen, so lange du dich einarbeitest: fprintf() ist C,
in C++ verwendet man dafür streams.
merciless
Dirk K. schrieb:> Ich empfehle dir auch, C und C++ weitestgehend zu> trennen, so lange du dich einarbeitest: fprintf() ist C,> in C++ verwendet man dafür streams.
Ich stimme dir zu. Es ist wichtig C und C++ zu trennen. Allerdings
fprintf genauso C++ wie es C ist. Und aktuell ist es die einzig
sinnvolle Möglichkeit für die formatierte Ausgabe von Daten im Standard.
streams haben keinen Vorteil gegenüber den stdio Funktionen, wenn ein
guter Compiler mit aktivierten Warnungen benutzt wird. Das ändert sich
zum Glück mit C++20 dank std::format.
mh schrieb:> Dirk K. schrieb:>> Ich empfehle dir auch, C und C++ weitestgehend zu>> trennen, so lange du dich einarbeitest: fprintf() ist C,>> in C++ verwendet man dafür streams.>> Ich stimme dir zu. Es ist wichtig C und C++ zu trennen. Allerdings> fprintf genauso C++ wie es C ist. Und aktuell ist es die einzig> sinnvolle Möglichkeit für die formatierte Ausgabe von Daten im Standard.> streams haben keinen Vorteil gegenüber den stdio Funktionen, wenn ein> guter Compiler mit aktivierten Warnungen benutzt wird. Das ändert sich> zum Glück mit C++20 dank std::format.
Oder seit C++17 mit:
https://en.cppreference.com/w/cpp/utility/to_chars
Wilhelm M. schrieb:> Oder seit C++17 mit:
Das ist kein Ersatz für fprintf. Es ist eine auf einen Wert
eingeschränkte Variante von printf für Iteratoren. Wenn man etwas
komplexere Ausgaben hat, hat man schnell die gleichen Probleme wie mit
den streams.
mh schrieb:> Das ist kein Ersatz für fprintf.
Habe ich nicht behauptet.
Allerdings hast Du gesagt, std::fprintf() wäre die einzige sinnvolle
Möglichkeit sei, eine formatierte Ausgabe zu erzeugen.
Ich finde std:.to_chars() sehr sinnvoll, weil es per definitionem auch
die schnellste Möglichkeit sein soll in der stdlibc++.