Globale Objekte(cout, etc.): Wie macht man das?
-
Ich habe vor mir einen globalen Stream zu machen, der Fehlermeldungen in eine Textdatei(log.txt) schreibt. Das soll so laufen, wie z.B. bei cout. Man soll sich um nichts kümmern müssen, bevor man den Stream benutzt. Alles, was ich zu cout gefunden hab, ist die extern Deklaration.
Kann mir vielleicht jemand sagen, wie man sowas macht? Oder kann man irgentwo nachkucken, wie das bei cout oder so gemacht wird?
-
bau ne datei log.h mit
extern fstream log;//nur deklaration, als bescheidsagen, daß es das objekt irgendwo gibt
und ne log.cpp mit
fstream log("c:\\pappnase\\logfile.txt");//das objekt echt anlegen
aber obacht: das klappt nur sicher, wenn log nicht vor der main() benutzt wird. falls du in ner anderen *.cpp ein anderes globaes objekt baust und dessen konstruktor evtl was nach log schreibt, kann es crashen. könnte ja sein, daß das andere globale objekt gebaut wird, bevor dein globales log gebaut wird. aber das wissen die beiden nicht, wer welches benutzt, und welches deshalb zuerst leben muß.
falls du diesen problemfall hast, lies "Effektiv C++ programmieren".
-
Danke, das ist ja gar nicht so schwer.
Zu dem, mit "Effektiv C++ programmieren": Meinst Du, ich soll 'nen Singleton nehmen, wenn das Problem auftritt?
Da bei einem Absturz Fehlermeldungen, die noch im Buffer sind verloren gehen(stimmt doch oder?), hab ich versucht mir eine Streamklasse zu schreiben, die die Datei nach jedem Schreiben wieder schliesst. Hab' mir da was von josuttis.de abgekuckt. Ich krieg's aber nicht hin.
So hab' ich's gemacht:
namespace tools { class logbuf : public std::streambuf { std::string filename; public: logbuf(const std::string& filename_) : filename(filename_) {} virtual std::streamsize xsputn(const char* s, std::streamsize num) { std::ofstream file(filename.c_str(), std::ios::app); file.write(s, num); //nur rumprobiert, weiss nicht, wie's richtig wäre. return num; } }; /*class logstream : public std::ostream { protected: logbuf buf; public: logstream(const std::string& filename) : std::ostream(0), buf(filename) { rdbuf(&buf); } };*/ }
Die Logstream-Klasse lässt sich aber nicht compilieren(Kein geeigneter Standardkonstruktor verfuegbar) und die logbuf-Klasse funktioniert nach dem ersten Flushen nicht mehr.
Mein Test:
#include "tools/log.h" int main() { tools::logbuf buf("log.txt"); std::ostream log(0); log.rdbuf(&buf); log << "hi" << std::flush; log << 100; log << "bla" << std::flush; return 0; }
Danach steht blos "hi" in log.txt.
Kann mir vielleicht jemand sagen, wie das geht? Oder wisst Ihr ne bessere Lösung?
-
Schau dir mal meinen Cryptstream an, evtl. hilft es dir ja weiter:
CryptstreamInteressante Links zum Thema stream sind auch:
http://www.langer.camelot.de/IOStreams/Excerpt/excerpt.htm#Main
http://www.gabi-soft.fr/articles/fltrsbf1.htmlDevil
-
Saugie schrieb:
Zu dem, mit "Effektiv C++ programmieren": Meinst Du, ich soll 'nen Singleton nehmen, wenn das Problem auftritt?
nein, ich dachte schon an globale objekte.
das mit dem singleton geht natürlich auch.in den selten fällen, wo ich logs schreibe, mache ich es ungefähr so:
ofstream("log.txt")<<"hi"; ofstream("log.txt")<<100; ofstream("log.txt")<<"bla";
-
Ich hab's jetzt 'n bischen einfacher gemacht.
struct logfile_cleaner { logfile_cleaner() { std::ofstream file("log.txt"); file.clear(); } }; namespace tools { void log(const std::string& msg) { static logfile_cleaner ___; std::ofstream file("log.txt", std::ios::app); file << msg; } }
Trotzdem, danke für die Links. Ich werd's mir mal ankucken, da ich evtl. mal 'ne Streamklasse für Sockets baun will.
@Volkard:
Welche Lektion meinst du denn(falls Du's grad da hast...)? Hab' vorhin 47 gelesen.
-
Du weißt, dass clear() nur die Fehlerflags eines Streams löscht?
-
Nö... komisch, wenn ich den Konstruktor gar nichts machen lass, wird die Datei trotzdem geleert. Woran liegt das?
-
Saugie schrieb:
Nö... komisch, wenn ich den Konstruktor gar nichts machen lass, wird die Datei trotzdem geleert. Woran liegt das?
an dem
std::ofstream file("log.txt");das überschreibt die datei
-
ups, das append hab ich wohl vergessen.
-
Jo, das hab ich mittlerweile auch gelesen. Allerdings rufe ich das ja gar nicht mehr auf und in der Datei steht trotzdem nur, was ich mit dem Programm da reinschreib. Also es müsste ja dann mehrmals drinstehen, wenn ich das Programm nochmal aufrufe, richtig?
edit: Argh, stimmt gar nicht... Hab' da wohl irgentwas vertüteld. Seit ich den Konstruktor nicht mehr aufrufe löscht der dei Datei auch nicht mehr.
edit2: Obwohl ich den Konstruktor von logfile_cleaner wieder aufrufe, leert das Programm die Datei nicht. Es kommt mir so vor, als ob der Konstruktor gar nicht aufgerufen wird. Wenn ich 'nen Haltepunkt da reintu, sagt VC++, dass der sich in keiner gültigen Zeile befindet oder so.
edit3: Gnaaa, mein Testprog wurde nicht automatisch mit der neuen Version meiner tools.lib verlinkt... nachdem ich die test.exe gelöscht hab und nachmal compiliert und gelinkt (;)) hab ging's...