(erledigt) [C++] stringstream::flush() überladen

Programmiersprachen, APIs, Bibliotheken, Open Source Engines, Debugging, Quellcode Fehler und alles was mit praktischer Programmierung zu tun hat.
Antworten
Benutzeravatar
Krishty
Establishment
Beiträge: 8267
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

(erledigt) [C++] stringstream::flush() überladen

Beitrag von Krishty »

Hi,

Ich möchte einen eigenen String-Stream entsprechend ::std::wstringstream, der sich von diesem nur in der Funktion flush() unterscheidet.

Einfach abzuleiten ist aber nicht möglich, weil viele Spezialisierungen des Operators << globale Funktionen sind. Die Überladene Funktion wird also nie erreicht, das ist allgemein bekannt.

Als Lösung wird oft eine Containerklasse vorgeschlagen, die den operator << als Template anbietet und an den enthaltenen ::std::wstringstream weiterleitet. In meinem Fall hilft mir das aber nicht, denn flush() lässt sich damit immernoch nicht überladen.

Wie bekomme ich nun einen Stream mit voller Kompatibilität zu ::std::wstringstream, aber mit überladenem flush() hin?

Gruß, Ky
Zuletzt geändert von Krishty am 22.07.2009, 23:22, insgesamt 1-mal geändert.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Biolunar
Establishment
Beiträge: 154
Registriert: 27.06.2005, 17:42
Alter Benutzername: dLoB

Re: [C++] stringstream::flush() überladen

Beitrag von Biolunar »

Hi,
Krishty hat geschrieben:Einfach abzuleiten ist aber nicht möglich, weil viele Spezialisierungen des Operators << globale Funktionen sind. Die Überladene Funktion wird also nie erreicht, das ist allgemein bekannt.
Da verstehst du glaub ich was falsch. Die Operatoren << und >> arbeiten auf der Basis von std::basic_ostream bzw. std::basic_istream und nicht für std::basic_stringstream. Und da ist glaube ich auch dein Problem: da flush() nicht virtual ist, wird es in deiner abgeleiteten Klasse durch die Basisklassenreferenzen nicht aufgerufen. Ein manuelles .flush() auf deinem abgeleiteten Stream wird zwar funktionieren, aber auch der Manipulator std::flush wird den Dienst verweigern, da std::flush auch std::basic_ostream::flush() aufruft und nicht deinen.

Ich wollte grad antworten: "Leite doch von std::basic_stringbuf ab und setze diesen anstatt den standard std::basic_stringbuf auf deinen Stream." Doch dann musste ich feststellen, dass std::basic_stringstream nur die "Get-Version" von rdbuf() bereitstellt :( Warum das so ist, ist mir schleierhaft...


Ansonsten fällt mir grad auch nicht ein, wie man flush() für einen stringstream bereitstellen könnte. Aber Wenn ich mal fragen darf, warum braucht dein stringstream denn ein flush()? Das ergibt auf den ersten Blick nämlich gar keinen Sinn ;-)
Benutzeravatar
Krishty
Establishment
Beiträge: 8267
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [C++] stringstream::flush() überladen

Beitrag von Krishty »

Biolunar hat geschrieben:Die Operatoren << und >> arbeiten auf der Basis von std::basic_ostream bzw. std::basic_istream und nicht für std::basic_stringstream. […] da flush() nicht virtual ist, wird es in deiner abgeleiteten Klasse durch die Basisklassenreferenzen nicht aufgerufen.
Stimmt natürlich!
Biolunar hat geschrieben:Ich wollte grad antworten: "Leite doch von std::basic_stringbuf ab und setze diesen anstatt den standard std::basic_stringbuf auf deinen Stream." Doch dann musste ich feststellen, dass std::basic_stringstream nur die "Get-Version" von rdbuf() bereitstellt :( Warum das so ist, ist mir schleierhaft...
Das ist das Problem, die vielen Stream-Objekte sind für jemanden, der da nicht drinsteckt, sehr schwer zu verstehen (und für den Rest scheinbar auch nicht ganz transparent) … ich habe schon die C++-Referenzen abgeklappert, aber das ist einfach zuviel Information um sofort durchzublicken.
Biolunar hat geschrieben:Aber Wenn ich mal fragen darf, warum braucht dein stringstream denn ein flush()? Das ergibt auf den ersten Blick nämlich gar keinen Sinn ;-)
Ich dachte mir, ich könnte einen stringstream mit Debug-Output füllen und den dann zeilenweise auf den Bildschirm flushen … so etwas wie ::std::cout … Momentan fülle ich überall ::std::wstringstreams und rufe dann meine Output-Funktion mit deren .str()-Objekten auf … ich lasse mich da aber gern besserer Wege belehren :D
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Biolunar
Establishment
Beiträge: 154
Registriert: 27.06.2005, 17:42
Alter Benutzername: dLoB

Re: [C++] stringstream::flush() überladen

Beitrag von Biolunar »

Also quasi anstatt sowas: logger_object.write(text.str()); sowas wie text.flush();? Die Idee da hinter fände ich nicht schlecht, da das flush() standardmäßig sowieso nix macht, allerdings wird damit der Sinn von flush() verändert. Dieses wiederrum halte ich für eine schlechte Idee. Wie wäre es, wenn du std::clog oder std::wclog für deine Ausgaben ummünzt? Dann hättest du immer ein clog << text.str();.
Benutzeravatar
Krishty
Establishment
Beiträge: 8267
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [C++] stringstream::flush() überladen

Beitrag von Krishty »

Biolunar hat geschrieben:Also quasi anstatt sowas: logger_object.write(text.str()); sowas wie text.flush();? Die Idee da hinter fände ich nicht schlecht, da das flush() standardmäßig sowieso nix macht, allerdings wird damit der Sinn von flush() verändert. Dieses wiederrum halte ich für eine schlechte Idee.
Neinein – bisher mache ich es so:

Code: Alles auswählen

::std::wstringstream ErrorMsg;
ErrorMsg << L"Parameter 1 sollte > 5 sein, ist aber " << Parameter1 << L"!" << ::std::endl;
Log(ErrorMsg.str());
Ich hätte aber gern

Code: Alles auswählen

Log << L"Parameter 1 sollte > 5 sein, ist aber " << Parameter1 << L"!" << ::std::endl;
Wobei mir das flush() wichtig war, weil die Log-Funktion recht teuer ist und der Output deshalb gepuffert geschrieben werden sollte (in dem Fall erst beim Erhalten von ::std::endl, das den Puffer ja standardmäßig flusht).
Biolunar hat geschrieben:Wie wäre es, wenn du std::clog oder std::wclog für deine Ausgaben ummünzt? Dann hättest du immer ein clog << text.str();.
Dass man diese Ausgaben umleiten kann, war mir bin jetzt noch gänzlich unbekannt! Google sagt mir, ich brauche ein eigenes ::std::streambuf-Objekt dafür … ich werde mal schauen, wie ich das hinbekomme, und melde mich bei Problemen wieder. Danke für den Hinweis, das ist schließlich exakt, was ich haben möchte!

Ich habe mir in der Vermutung, dass es sowas gibt, schon ::std::clog und ::std::cout angeschaut, ihre Implementierung aber nirgendwo gefunden und dann aufgegeben …
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Biolunar
Establishment
Beiträge: 154
Registriert: 27.06.2005, 17:42
Alter Benutzername: dLoB

Re: [C++] stringstream::flush() überladen

Beitrag von Biolunar »

Ja, exakt man brauch einen neuen streambuffer. Mit Hilfe von Boost.IOStreams ist es ziemlich einfach so einen streambuffer zu erstellen oder aber du leitest selber von std::basic_streambuf ab... Du könntest dir z.B. die Implementierung des std::basic_filebuf mal ansehen, da dieser warscheinlich gepuffert ist.
Benutzeravatar
Krishty
Establishment
Beiträge: 8267
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [C++] stringstream::flush() überladen

Beitrag von Krishty »

Zu spät, habe schon meinen eigenen Stream geschrieben. ::std::basic_filebuf nutzt C-Files, die von sich aus schon gepuffert sind und puffert deshalb nicht selbst.

Ich habe für meinen Text einfach einen ::std::vector<wchar_t> genommen. Das Ding ist, dass es mit ::std::wcerr funktioniert, mit ::std::wclog und ::std::wcout allerdings nicht – dort erreicht immernur der zuletzt geschickte Teil der Nachricht sein Ziel … immer, wenn eine Nachricht für den Puffer zu lang ist und einen Aufruf von overflow() provoziert, bleibt der Puffer einfach leer.

Du hast nicht zufällig einen Tipp, warum es mit ::std::wcerr funktioniert und mit den anderen Streams nicht?
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Biolunar
Establishment
Beiträge: 154
Registriert: 27.06.2005, 17:42
Alter Benutzername: dLoB

Re: [C++] stringstream::flush() überladen

Beitrag von Biolunar »

Ich kann das Verhalten nicht reproduzieren, mit allen (wcout, wcerr, wclog) funktioniert es bei mir mit dem vector einwandfrei.

Wenn du deine Log-Ausgaben in eine Datei schreiben willst, gibts auch eine einfache Variante ohne einen eigenen streambuffer:

Code: Alles auswählen

class Logger
{
public:
    Logger() :
        sb(0),
        wsb(0),
        file("output.txt", std::ios_base::app),
        wfile("output.txt", std::ios_base::app)
    {
        sb = std::clog.rdbuf(file.rdbuf());
        wsb = std::wclog.rdbuf(wfile.rdbuf());
    }

    ~Logger()
    {
        std::clog.rdbuf(sb);
        std::wclog.rdbuf(wsb);
    }

private:
    std::streambuf* sb;
    std::wstreambuf* wsb;
    std::ofstream file;
    std::wofstream wfile;
};
Da musst du halt nur in deiner main() ein Logger Objekt erstellen und damit ist für den Rest deines Programms clog und wclog auf die Datei umgeleitet.

Hab ich dich richtig verstanden, dass du deine Ausgabe nur machen willst, wenn der Stream geflusht wird? Also ein beliebig großer Puffer, der *nur* bei einem flush geleert wird? Ich könnt dir mal einen schreiben allerdings frühstens Morgen, denn gleich gehts los zu ner Radtour und dann betrinke ich mich :)
Die Benutzung wird so wie die Klasse Logger (siehe Oben) gehandhabt, nur entfallen logischerweise die beiden file streams. Wenn du doch was anderes meintest, dann gib mal genau deine Wünsche an, damit du mit dem buffer auch glücklich werden kannst :)
Unknown GER
Beiträge: 49
Registriert: 09.01.2003, 13:04

Re: [C++] stringstream::flush() überladen

Beitrag von Unknown GER »

Krishty hat geschrieben:Du hast nicht zufällig einen Tipp, warum es mit ::std::wcerr funktioniert und mit den anderen Streams nicht?
Ich habe mir den Thread nicht genau angesehen, aber wenn std::(w)cerr aus der Reihe tanzt, hat das meist damit zu tun, das dieser Ausgabekanal standardmäßig nicht gepuffert ist (im Gegensatz zu std::(w)cout und std::(w)log). Das ist deshalb so, da bei einem Programmabsturz der Pufferinhalt verloren wäre, was in den meisten Fällen nicht das gewünschte Verhalten ist, was man von diesem Ausgabekanal erwartet. Das kann man zwar z. B. mit std::(w)clog umgehen, man sollte sich aber Fragen, ob es wirklich das ist, was man will.
Zuletzt geändert von Unknown GER am 13.06.2009, 22:35, insgesamt 1-mal geändert.
Unknown GER
Beiträge: 49
Registriert: 09.01.2003, 13:04

Re: [C++] stringstream::flush() überladen

Beitrag von Unknown GER »

Sorry, konnte nicht umhin, an der Logger-Beispiel-Klasse etwas umzusortieren (Initialisierungsliste und Reihenfolger der Deklarationen). Die Member file und wfile würden sonst implizit für die Katz in der Initialisierungsliste initialisiert werden und dann im Konstruktor gleich wieder überschrieben.

Code: Alles auswählen

class Logger
{
public:
    Logger() :
        file("output.txt", std::ios_base::app),
        wfile("output.txt", std::ios_base::app),
        sb(std::clog.rdbuf(file.rdbuf())),
        wsb(std::wclog.rdbuf(wfile.rdbuf()))
    {
    }

    ~Logger()
    {
        std::clog.rdbuf(sb);
        std::wclog.rdbuf(wsb);
    }

private:
    std::ofstream file;
    std::wofstream wfile;
    std::streambuf* sb;
    std::wstreambuf* wsb;
};
Benutzeravatar
Krishty
Establishment
Beiträge: 8267
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [C++] stringstream::flush() überladen

Beitrag von Krishty »

Oha, das Thema habe ich ganz vergessen.

Nun, das Buffered/Unbuffered-Problem war wohl in einem Vertipper im Umgang mit den Datencontainer begründet. Es funktioniert nun soweit. Ich werde meinen Code hier posten, vorher aber noch eine Frage: Kann ich mich darauf verlassen, dass der frisch allokierte Inhalt eines ::std::vector<char> immer genullt ist?
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Unknown GER
Beiträge: 49
Registriert: 09.01.2003, 13:04

Re: [C++] stringstream::flush() überladen

Beitrag von Unknown GER »

Ja, ein std::vector ruft in diesem Fall den Defaultkonstruktor von jedem Element auf. Die "Defaultkonstruktoren" der intrinsischen Datentypen nullen sich selbst.
Benutzeravatar
Krishty
Establishment
Beiträge: 8267
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [C++] stringstream::flush() überladen

Beitrag von Krishty »

Alles klar. Hier ist mein minimalistischer Streambuffer (ohne get-Funktionalität), der alle Strings an den Debugger weiterleitet:

Code: Alles auswählen

inline void ReportToDebugger(const wchar_t p_Text[]) {
	// See http:// msdn.microsoft.com/en-us/library/ms680345.aspx.
	if(::IsDebuggerPresent())
		// See http:// msdn.microsoft.com/en-us/library/aa363362.aspx.
		::OutputDebugStringW(p_Text);
	return;
}

inline void ReportToDebugger(const char p_Text[]) {
	// See http:// msdn.microsoft.com/en-us/library/ms680345.aspx.
	if(::IsDebuggerPresent())
		// See http:// msdn.microsoft.com/en-us/library/aa363362.aspx.
		::OutputDebugStringA(p_Text);
	return;
}


// Redirects any output to the debugger.
//	Use ::std::ios::rdbuf() to bind this stream buffer to IOstreams like ::std::cout, ::std::cerr or ::std::clog.
template <
	typename t_CharacterType,
	typename t_CharacterTraits = ::std::char_traits<t_CharacterType>
> class DebuggerStreamBuffer
	: public ::std::basic_streambuf<t_CharacterType, t_CharacterTraits>
{
protected:
	// Stores the current text until the stream is flushed.
	::std::vector<t_CharacterType> m_TextBuffer;

	// Prepares the text buffer for new text and abandons its old content.
	void ResetBuffer(void) {
		// We can not just resize the buffer since its content must be cleared with zeroes.
		this->m_TextBuffer.clear();
		this->ExtendBuffer();
		return;
	}

	// Reserves memory for further text in the buffer and updates the buffer pointers.
	void ExtendBuffer(void) {
		static const size_t BufferStepSize = 8;
		this->m_TextBuffer.resize(this->m_TextBuffer.size() + BufferStepSize, t_CharacterType(0));
		// Set the new memory as the put pointer region. See http:// www. cplusplus.com/reference/iostream/streambuf/setp/.
		this->setp(this->m_TextBuffer.end()._Myptr - BufferStepSize, this->m_TextBuffer.end()._Myptr);
		return;
	}

public:

	// Standard constructor.
	explicit DebuggerStreamBuffer(void) {
		this->ResetBuffer();
		return;
	}

	// This function will be called whenever the text buffer needs further memory.
	// See http:// www. cplusplus.com/reference/iostream/streambuf/overflow/.
	virtual typename t_CharacterTraits::int_type overflow(
		typename t_CharacterTraits::int_type p_Character
	) {
		// Add the new character.
		this->m_TextBuffer.push_back(static_cast<t_CharacterType>(p_Character));
		// Reserve space for further text.
		this->ExtendBuffer();

		// Any value different from EOF makes the caller proceed.
		return t_CharacterTraits::not_eof(p_Character);
	}

	// This function will be called whenever the text buffer is flushed, e.g. when writing ::std::endl or ::std::flush. It
	//	sends the text to the debugger and clears the buffer.
	// See http:// www. cplusplus.com/reference/iostream/streambuf/sync/.
	virtual int sync(void) {
		// Do not print empty strings.
		if(L'\0' == this->m_TextBuffer[0])
			return 0;
		else {
			// Buffered text is never zero-terminated; we must append the zero ourselves.
			this->m_TextBuffer.push_back(L'\0');

			// Print the old text …
			ReportToDebugger(&this->m_TextBuffer[0]);
			// …  and prepare for new text.
			this->ResetBuffer();

			// A return value of 0 indicates success.
			return 0;
		}
	}


	// Destructor.
	virtual ~DebuggerStreamBuffer(void) {
		// Flush any remaining text.
		this->sync();
		return;
	}

}; // class DebuggerStreamBuffer
Btw scheinen Links in Code-Kommentaren Probleme zu bereiten …
{code=cpp}// http://www.google.de{/code}

Code: Alles auswählen

// http://www.google.de
Zuletzt geändert von Krishty am 14.06.2009, 20:39, insgesamt 2-mal geändert.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Schrompf
Moderator
Beiträge: 4879
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas Ziegenhagen
Wohnort: Dresden
Kontaktdaten:

Re: [C++] stringstream::flush() überladen

Beitrag von Schrompf »

Der Default-Konstruktor eines chars tut gar nix. Ein std::vector<char> enthält also Müll, außer Du benutzt explizit den vector-Konstruktor, bei dem Du den Vorgabewert als Parameter angeben kannst:

Code: Alles auswählen

std::vector<char> zeuch( 5000 /* Anzahl Elemente */, 0 /* Vorgabeelement */);
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Unknown GER
Beiträge: 49
Registriert: 09.01.2003, 13:04

Re: [C++] stringstream::flush() überladen

Beitrag von Unknown GER »

Wohoo, Tatsache, da hab ich nun echt C# und C++ durcheinandergewürfelt, aber wie Du ja schon gesagt hast gibt es beim Vektorkonstruktor eine entsprechende Variante.
Benutzeravatar
Krishty
Establishment
Beiträge: 8267
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [C++] stringstream::flush() überladen

Beitrag von Krishty »

Danke, habe ich – auch im Beispiel – direkt korrigiert!
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Biolunar
Establishment
Beiträge: 154
Registriert: 27.06.2005, 17:42
Alter Benutzername: dLoB

Re: [C++] stringstream::flush() überladen

Beitrag von Biolunar »

Die umstrukturierung der Klasse "Logger" ist in der Tat sinnvoll danke :), wenn auch aus performance Gründen irrelevant. Also so grausig war das doch nicht oder? ;-)

Da gibt es schon grausigere Sachen wie sowas:
Krishty hat geschrieben:

Code: Alles auswählen

        // Standard constructor.
	explicit DebuggerStreamBuffer(void) {
		this->ResetBuffer();
		return;
	}
Das void in der Parameterliste ist redundant und in C++ nicht gerne gesehen. Außerdem hat das explicit an dieser Stelle keine Wirkung.
Krishty hat geschrieben:

Code: Alles auswählen

// Reserves memory for further text in the buffer and updates the buffer pointers.
        void ExtendBuffer(void) {
                static const size_t BufferStepSize = 8;
                this->m_TextBuffer.resize(this->m_TextBuffer.size() + BufferStepSize);
                // Set the new memory as the put pointer region. See http:// www. cplusplus.com/reference/iostream/streambuf/setp/.
                this->setp(this->m_TextBuffer.end()._Myptr - BufferStepSize, this->m_TextBuffer.end()._Myptr, t_CharacterType(0));
                return;
        }
Implementationsabhängig: Wo steht denn, dass ein std::vector<...>::iterator eine Variable namens _Myptr hat? Wenn, dann lieber &m_TextBuffer[0], da das seit C++03 ein definiertes (zusammenhängendes!) Array ergibt. (Hast du auch korrekt in der sync() Elementfunktion angewendet)

Ich hab den Streambuffer mal umgeschrieben:

Code: Alles auswählen

// Die beiden Änderungen mussten sein, weil ich kein VS verwende
void ReportToDebugger(char const* str)
{
    std::ofstream file("output.txt", std::ios_base::app);
    file << str;
}
void ReportToDebugger(wchar_t const* str)
{
    std::wofstream file("output.txt", std::ios_base::app);
    file << str;
}


template <typename char_t, typename traits_t = std::char_traits<char_t> >
class logbuf : public std::basic_streambuf<char_t, traits_t>
{
public:
    typedef std::basic_streambuf<char_t, traits_t> base_class;
    typedef typename base_class::char_type char_type;
    typedef typename base_class::traits_type traits_type;
    typedef typename base_class::int_type int_type;

    logbuf()
    {
        reset();
    }

protected:
    virtual int sync()
    {
        try
        {
            ReportToDebugger(buffer.c_str());
            reset();
        }
        catch (...)
        {
            return -1;
        }
        return 0;
    }

    virtual int_type overflow(int_type c = traits_type::eof())
    {
        if (traits_type::eq_int_type(c, traits_type::eof()))
            sync(); // return value omitted
        else
            buffer.push_back(c);

        return traits_type::not_eof(c);
    }

private:
    void reset()
    {
        buffer.clear();
        buffer.reserve(magic_size); // Prevent frequent reallocations
    }

    typedef std::basic_string<char_type, traits_type> string_type;
    static typename string_type::size_type const magic_size = 32;
    string_type buffer;
};


class Logger
{
public:
    Logger() :
        sb(std::clog.rdbuf(&narrow)),
        wsb(std::wclog.rdbuf(&wide))
    {
    }

    ~Logger()
    {
        std::clog.rdbuf(sb);
        std::wclog.rdbuf(wsb);
    }

private:
    logbuf<char> narrow;
    logbuf<wchar_t> wide;
    std::streambuf* sb;
    std::wstreambuf* wsb;
};
So wäre der streambuf eigentlich ungepuffert, weil kein interner buffer mit setp() festgelegt worden ist, aber duch den privaten String wird eine dynamische Pufferung vorgenommen. Die Streampuffer sind nämlich nur für Puffer mit fester größe vorgesehen, daher der umweg über den eigenen String.
Benutzeravatar
Krishty
Establishment
Beiträge: 8267
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [C++] stringstream::flush() überladen

Beitrag von Krishty »

Biolunar hat geschrieben:Das void in der Parameterliste ist redundant und in C++ nicht gerne gesehen.
Autsch, voll in ein Newbie-Fettnäpfchen getreten :D
Biolunar hat geschrieben:Außerdem hat das explicit an dieser Stelle keine Wirkung.
Stimmt … Gewohnheit :roll:
Implementationsabhängig: Wo steht denn, dass ein std::vector<...>::iterator eine Variable namens _Myptr hat? Wenn, dann lieber &m_TextBuffer[0], da das seit C++03 ein definiertes (zusammenhängendes!) Array ergibt. (Hast du auch korrekt in der sync() Elementfunktion angewendet)
Das geht an der Stelle eher schlecht als Recht – auf end() kann man nicht per operator [] zugreifen, weil sonst korrekterweise eine vector-subscript-out-of-range-Assertion hochgeht. Das wird dann zu &this->m_TextBuffer[0] + this->m_TextBuffer.size() … wäre &*this->m_TextBuffer.end() eine Möglichkeit, oder geht es noch besser?

Zu deinem Code: Was ist der Vorteil von ::std::basic_string (habe ich in der Doku nicht finden können)? Auch gut zu wissen, dass ich in overflow() auf ein mögliches eof achten muss.
Biolunar hat geschrieben:So wäre der streambuf eigentlich ungepuffert, weil kein interner buffer mit setp() festgelegt worden ist, aber duch den privaten String wird eine dynamische Pufferung vorgenommen.
So hatte ich es gemacht, als meine Pufferung nicht funktionierte und ich keinen Bock auf Debugging hatte :D
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Biolunar
Establishment
Beiträge: 154
Registriert: 27.06.2005, 17:42
Alter Benutzername: dLoB

Re: [C++] stringstream::flush() überladen

Beitrag von Biolunar »

Krishty hat geschrieben:Zu deinem Code: Was ist der Vorteil von ::std::basic_string (habe ich in der Doku nicht finden können)?
Wus? Kommt dir das bekannt vor:

Code: Alles auswählen

namespace std
{
    typedef basic_string<char> string;
}
Ja! Std::string ist ein std::basic_string! Naja ich hab einfach einen String genommen und keinen vector, weil es ja auch ein String ist, der ausgegeben wird und so groß ist der Unterschied zwischen basic_string und vector ja auch nicht.


Ich seh grad du übergibst setp() drei Argumente??? Jetzt bin ich verwirrt; das nimmt doch nur zwei :?: Da du sowieso einen vector verwendest, kannst du dir die interne Pufferung des streambuffers sowieso sparen (siehe mein Code). Damit entfällt auch die Notwendigkeit für setp, also keine Iteratorverunstaltung mehr :)
Benutzeravatar
Krishty
Establishment
Beiträge: 8267
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [C++] stringstream::flush() überladen

Beitrag von Krishty »

Biolunar hat geschrieben:Ja! Std::string ist ein std::basic_string!
Okay, das erklärt einiges.
Biolunar hat geschrieben:Ich seh grad du übergibst setp() drei Argumente??? Jetzt bin ich verwirrt; das nimmt doch nur zwei :?:
Ich bin in der Zeile verrutscht, als ich nachgebessert habe, dass der Vektor mit Nullen gefüllt werden soll. Ist korrigiert.
Biolunar hat geschrieben:Da du sowieso einen vector verwendest, kannst du dir die interne Pufferung des streambuffers sowieso sparen (siehe mein Code). Damit entfällt auch die Notwendigkeit für setp, also keine Iteratorverunstaltung mehr :)
Ich hatte mir gedacht, dass die Möglichkeit zum direkten Schreiben in den Puffer schneller ist, als für jeden Buchstaben overflow() aufzurufen.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Aramis
Moderator
Beiträge: 1458
Registriert: 25.02.2009, 19:50
Echter Name: Alexander Gessler
Wohnort: 2016
Kontaktdaten:

Re: [C++] stringstream::flush() überladen

Beitrag von Aramis »

Ich hab mal gehört, dass der C++-Sprachstandard bei so manchem eine Antwort bereit hält, u.A. die finale Antwort auf die Frage nach der Standardisierung mancher Funktionen, den Klassen der Standardbibliothek, und dem ganzen Rest :twisted:

*Zieht Kopf zurück und versteckt sich im Keller* :(
Benutzeravatar
Biolunar
Establishment
Beiträge: 154
Registriert: 27.06.2005, 17:42
Alter Benutzername: dLoB

Re: [C++] stringstream::flush() überladen

Beitrag von Biolunar »

Man könnte zusätzlich noch das xsputn() überschreiben:

Code: Alles auswählen

virtual std::streamsize xsputn(char_type const* str, std::streamsize n)
{
    typename string_type::size_type const old_size = buffer.size();
    try
    {
        buffer.append(str, n);
    }
    catch (...)
    {
        return buffer.size() - old_size;
    }
    return n;
}
Dann wird halt nicht so oft overflow() aufgerufen, sondern pro String einmal xsputn().
Benutzeravatar
Krishty
Establishment
Beiträge: 8267
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [C++] stringstream::flush() überladen

Beitrag von Krishty »

Optimal – danke!
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Antworten