Von streambuf erben
-
Hallo,
Ich habe eine Klasse realisiert, auf welche man mit Hilfe des <<-Operator direkt ins Syslog (Nix-Systeme) "schreiben" kann.
Syslog funktioniert zeilenorientiert; d.h. man kann mit der Funktion syslog() immer nur eine ganze Zeile auf einmal ins Syslog schreiben. Wenn man Einträge mit Hilfe von verschiedenen Operatoren zusammensetzen will, wird bei meiner Implementation momentan jeder Operator-Aufruf einzeln ins Syslog geschrieben.
Ich möchte nun mehrmals auf das Objekt "schreiben" können und erst mit std::endl die Ausgabe ins Syslog schreiben lassen.
Ich gehe davon aus, dass sich ein solches Verhalten mit dem Erben von StreamBuffer schnell implementieren lässt. Schliesslich brauche ich einen Buffer, in welchem ich die Log-Nachricht zwischen-speichere, bis ich sie ins log schreibe.
Meine Operatoren sehen so aus:
Logger& operator <<(Logger& log, const char * msg) { log.log(msg); return log; } Logger& operator<<(Logger& log, const std::string msg) { log.log(msg.c_str()); return log; } Logger& operator<<(Logger& log, const int msg) { // convert integer and write to log std::stringstream tmp; tmp << msg; log.log(tmp.str().c_str()); return log; } Logger& Logger::operator<<(StandardEndLine manip) { // JETZT Buffer ins Syslog schreiben und leeren. // aufruf syslog(msg); return *this; }
So tief habe ich mich noch nie in den Standard Namespace hinein getraut. Aus der Doku unter http://www.cplusplus.com/reference/iostream/streambuf/ werde ich nicht ganz schlau.
Welche Methoden muss ich überschreiben bzw. implementieren? Wie definiere ich den zu verwendenden Buffer?
Vielen Dank für Tipps oder Verweise auf einfach Beispiele.
-
Meinst du nicht, dass es WESENTLICH einfacher wäre, wenn du deiner Klasse einen voll funktionsfähigen Puffer (zum Beispiel std::stringstream) als Member spendierst?
-
SeppJ schrieb:
Meinst du nicht, dass es WESENTLICH einfacher wäre, wenn du deiner Klasse einen voll funktionsfähigen Puffer (zum Beispiel std::stringstream) als Member spendierst?
Ja, da hast du recht. Aber ich möchte doch dazu lernen und habe die Vermutung dass ich mit einer Spezialisierung weitere Vorteile ernte.
Aber ja, ich habe das ganze jetzt mal mit einem strinbuffer realisiert.
-
Wenn du es dir unbedingt schwerer machen musst, als es ist, findest du hier ein Beispiel zum Verwenden von streambuf:
http://www.student.cs.uwaterloo.ca/~cs343/documents/libio/iostream_5.htmlIch würde an deiner Stelle jedoch eher einen ostream nehmen und dessen streambuf dann auf syslog setzen. Oder die zuerst vorgeschlagene Methode mit dem stringstream, weil du dann einfacher das detailierte Verhalten kontrollieren kannst.
-
maus_on_c schrieb:
Ich habe eine Klasse realisiert, auf welche man mit Hilfe des <<-Operator direkt ins Syslog (Nix-Systeme) "schreiben" kann.
.. meines Erachtens suboptimal.
maus_on_c schrieb:
Syslog funktioniert zeilenorientiert; d.h. man kann mit der Funktion syslog() immer nur eine ganze Zeile auf einmal ins Syslog schreiben. Wenn man Einträge mit Hilfe von verschiedenen Operatoren zusammensetzen will, wird bei meiner Implementation momentan jeder Operator-Aufruf einzeln ins Syslog geschrieben.
Ich möchte nun mehrmals auf das Objekt "schreiben" können und erst mit std::endl die Ausgabe ins Syslog schreiben lassen.
Ich gehe davon aus, dass sich ein solches Verhalten mit dem Erben von StreamBuffer schnell implementieren lässt. Schliesslich brauche ich einen Buffer, in welchem ich die Log-Nachricht zwischen-speichere, bis ich sie ins log schreibe.
std::streambuf ist die richtige Wahl. Den ostream kannst Du direkt weiter benutzen, egal ob mit einem eigenen ostream-Objekt oder cout bzw. clog
maus_on_c schrieb:
Welche Methoden muss ich überschreiben bzw. implementieren? Wie definiere ich den zu verwendenden Buffer?
Das ist leider relativ wenig dokumentiert.
Für die Ausgabe sind es die streambuf-Methoden sync und overflow. Hier mal ein Beispiel mit einem Buffer konstanter Größe.#include <iostream> #include <vector> void syslog( const char* txt ) // .. nur zu Demozwecken { std::cout << "syslog[" << txt << "]" << std::endl; } class LogBuf : public std::streambuf { public: enum { BUF_SIZE = 80 }; LogBuf() : m_buf( BUF_SIZE+1 ) { setp( &m_buf[0], &m_buf[0] + (m_buf.size()-1) ); } protected: virtual int sync() { if( pptr() > pbase() ) writeToDevice(); return 0; // 0 := Ok } private: void writeToDevice() { *pptr() = 0; // End Of String syslog( pbase() ); setp( &m_buf[0], &m_buf[0] + (m_buf.size()-1) ); } // -- Member std::vector< char_type > m_buf; }; int main() { using namespace std; LogBuf log; streambuf* oldSb = clog.rdbuf( &log ); // hier wird clog benutzt // alternativ: boost::io::ios_rdbuf_saver rbsvr( clog, &log ); // erfordert: #include <boost/io/ios_state.hpp> cout << "cout:" << endl; clog << "clog: " << endl; for( int n=0; n < 4; ++n ) clog << " " << n << "/7=" << n/7. << endl; clog.rdbuf( oldSb ); return 0; }
In dem Beispiel wird der Text jedes mal weggeschrieben, bis ein flush erfolgt. Der endl-Manipulator löst einen solchen 'flush' aus. Das heißt aber auch, dass der Text z.B. Zeilenumbrüche enthalten kann - wie im Beispiel zu sehen ist.
Falls der Buffer sich dynamisch vergrößern soll, so muss auch overflow überladen werden. overflow wird aufgerufen, wenn der Buffer voll ist.
protected: virtual int_type overflow( int_type m = traits_type::eof() ) { if( traits_type::eq_int_type( m, traits_type::eof() ) ) { writeToDevice(); } else { // Buffer overflow const std::size_t nChar = pptr()-pbase(); m_buf.resize( 2*m_buf.size() ); // Buffer verdoppeln setp( &m_buf[0], &m_buf[0] + (m_buf.size()-1) ); pbump( nChar ); *pptr() = traits_type::to_char_type( m ); // überzähliges Zeichen anhängen pbump( 1 ); } return traits_type::not_eof( m ); }
Gruß
Werner
-
Ich staun ja jedes mal wieder, wenn Werner so was hinzaubert...
Woher hast du das ganze Stream-Wissen?
Doch wohl kaum einzeln aus Referenzen zusammen gesucht?!
Gibt dazu irgendwo nen Tut oder nen Buch?bb
-
unskilled schrieb:
Ich staun ja jedes mal wieder, wenn Werner so was hinzaubert...
Woher hast du das ganze Stream-Wissen?
Doch wohl kaum einzeln aus Referenzen zusammen gesucht?!
Gibt dazu irgendwo nen Tut oder nen Buch?bb
Wollte ich auch schon lange wissen, einfach nur beiträge.
-
Das Buch was ihr sucht: Standard C++ IOStreams and Locales von Klaus Kreft und Angelika Langer
Sehr gute Einführung und Referenz in die gesamten Iostreams. Empfehlenswert zu lesen.
-
Bücherleser schrieb:
Das Buch was ihr sucht: Standard C++ IOStreams and Locales von Klaus Kreft und Angelika Langer
Sehr gute Einführung und Referenz in die gesamten Iostreams. Empfehlenswert zu lesen.vielen dank^^
100$ für ein neues, klingt ja fast so, als ob es wahnsinnig dick und gut wäre^^
naja, zum glück gibts gebrauchte ^^bb