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

Gast #6052779
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
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
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
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
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
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
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
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
Gast #6053837
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.
#6053841
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++.

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 6 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.