2012-10-15 9 views
8

Ich bin in Bereitstellung von ostream Betreibern für einige Mathematik-Klassen (Matrix, Vektor, etc.) Ein Freund hat festgestellt, dass die GCC-Standardbibliothek Implementierung der ostream Operator für std::complex umfasst die interne Verwendung von ein String-Stream die Ausgabe zu formatieren, bevor es zum eigentlichen ostream vorbei:Verwendung von stringstream in Ostream-Funktion

/// Insertion operator for complex values. 
template<typename _Tp, typename _CharT, class _Traits> 
    basic_ostream<_CharT, _Traits>& 
    operator<<(basic_ostream<_CharT, _Traits>& __os, const complex<_Tp>& __x) 
{ 
    basic_ostringstream<_CharT, _Traits> __s; 
    __s.flags(__os.flags()); 
    __s.imbue(__os.getloc()); 
    __s.precision(__os.precision()); 
    __s << '(' << __x.real() << ',' << __x.imag() << ')'; 
    return __os << __s.str(); 
} 

Dieses Muster ist sichtbar im Boost-als auch. Wir versuchen herauszufinden, ob dies ein Muster ist, dem man folgen sollte. Es gab Bedenken, dass ein zusätzlicher Header für den String-Stream enthalten sein muss und dass zusätzliche Heap-Zuordnungen innerhalb des String-Streams erforderlich sind, die möglicherweise vermieden werden könnten.

Am vernünftigsten wurde vorgeschlagen, dass, wenn der Client diese Funktionalität benötigt, sie den String-Stream erstellen und die Pre-Pass selbst durchführen können.

Kann mir jemand helfen zu verstehen, warum dies als gute Praxis angesehen wird und ob ich es übernehmen sollte?

Antwort

6

Überlegen Sie, was passiert, wenn Sie eine Ausgabebreite auf der Ostream gesetzt, dann schreiben Sie eine std :: komplex, um es - Sie nicht über die Breite wollen nur die erste Ausgabeoperation beeinflussen (dh die '(' Zeichen)

std::complex i(0, 1); 
std::cout << std::setw(10) << std::left << i; 

die Ausgabe, die es Durch die Bildung ehrt die Feldbreite und andere Formatierungen Flags gesetzt auf dem Strom "(0,1)     " nicht "(         0,1)"

drucken Schreiben die gesamte Ausgabe als einzelne Zeichenfolge dann heraus Dies sollte.

2

Ein Hauptzweck dieses Patterns besteht darin, zu vermeiden, dass die Manipulatoren/Flags des ursprünglichen Streams beibehalten und vor dem Zurücksetzen zurückgesetzt werden. Boost.IoStateSavers beseitigt die Notwendigkeit dafür, so würde ich sagen, dass die Verwendung dieser Bibliothek eine bessere Praxis wäre.

4

Der in einer anderen Antwort angegebene Threading-Grund wird nicht wirklich funktionieren: Die Zeichenfolge kann immer noch auf der Stream-Pufferebene aufgeteilt werden, da diese Operationen nicht atomar sind, wenn sie von mehreren Threads aufgerufen werden.

Allerdings gibt es zwei Überlegungen, die relevant sind:

  1. Für bestimmte Ausgänge vorübergehend wollen, um die Einstellungen Format-Flag ändern. Sie möchten beispielsweise sicherstellen, dass eine bestimmte Zeichenfolge in Hexadezimalschreibweise angezeigt wird, für andere Dezimalschreibweise und Sie möchten den Stream in seinen ursprünglichen Zustand zurückversetzen.
  2. Noch wichtiger ist die Bedeutung der width() Ausgabe ist die Anzahl der Zeichen, die die gesamte Formatierungszeichenfolge mindestens belegen sollte. Wenn Sie Ausgabeoperatoren intern für einen anderen Ausgabeoperator verwenden, würden Sie das erste Element so einrichten, dass es die Breite einnimmt, und nicht die gesamte resultierende Zeichenfolge, die aus mehreren Komponenten besteht. Zum Beispiel würde das reelle Element für eine komplexe Zahl width() und nicht die Kombination des reellen Elements, des Kommas und des imaginären Elements belegen.