[C++] Klasse von std::FILE ableiten

Gast #6052779
Lesenswert?

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
using namespace std;
6

7
class Datei: public FILE {
8
public:
9
        ~Datei() {
10
                fclose(this);
11
        }
12
        Datei(string s) {
13
                *this = *static_cast<Datei*>(fopen(s.c_str(), "w"));
14
        }
15
};
16

17
int main() {
18
        Datei d("hallo.txt");
19
        fprintf(&d, "Hallo Welt!");
20
        return 0;
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?
Gast #6052878
Lesenswert?

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.
Moderator #6052893
Lesenswert?

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.
Gast #6052898
Lesenswert?

Aus https://en.cppreference.com/w/cpp/io/c
1
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).

Das ist genau das, was du nicht machen darfst.
#6052920
Lesenswert?

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).
#6052951
Lesenswert?

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
Gast #6053804
Lesenswert?

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.
#6053818
Lesenswert?

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

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren