std::stringstream-Verhalten verändert nach Kompilerwechsel



  • Hallo,

    ich habe schon im Visual C++ Forum nachgefragt, aber anscheined weiß keiner eine Antwort darauf (vielelicht zu C++-Standardbibliothek-spezifisch).

    Ich habe ein reines C++-Programm, welches ich mit VC++ 6.0 erstellt habe, mit dem VS 2008 neu übersetzt. Dabei unterscheidet sich das Verhalten in einem Punkt:

    // AutoOut.h:
    #include <sstream>
    #include <iostream>
    
    class AutoOut: public std::wostringstream{
    
          // Konstruktor/Destruktor //
       public:
          AutoOut(){ }
    
          ~AutoOut(){
              std::wcout << str() << std::endl;
          }
    }
    
    //main.cpp:
    #include "AutoOut.h"{
    
    int wmain(int argc, wchar_t* argv[]){
    
        AutoOut() << L"Hello World!";
    
        AutoOut out;
        out << L"Hello World!";
    }
    

    Ausgabe VC++ 6.0 (SP5):

    Hello World!
    Hello World!

    Ausgabe Visual Studio 2008 (mit/ohne SP1):

    007657897
    Hello World!

    Woran liegt das?



  • Ich kann dir zwar nicht genau sagen, warum es im zweiten Fall funktioniert und im ersten nicht, aber grundsaetzlich existiert das Problem, weil wchar_t oftmals nur ein typedef auf unsigned short oder aehnliches ist und damit der operator << (unsigned short*) aufgerufen wird, anstelle eines fuer wchar_t ueberladenen, der korrekt einen String ausgeben wuerde.
    Workaround ist damit auch klar: casten



  • Da funktioniert gar nix mehr. Übrigens auch mit char statt wchar.
    Einem stringstream kann man prinzipiell auch einen std::string einstreamen, oder?

    AutoOut() << std::string("Mammamia")
    

    Das geht hier in die Hose.

    g++ test_1.cpp -o test_1
    test_1.cpp: In function 'int main()':             
    test_1.cpp:54: error: no match for 'operator<<' in 'AutoOut() << std::basic_string<char, std::char_traits<char>, std::allocator<char> >(((const char*)"Mammamia"), ((const std::allocator<char>&)((const std::allocator<char>*)(& std::allocator<char>()))))'                                                                         
    /usr/lib/gcc/x86_64-pc-linux-gnu/4.3.3/include/g++-v4/ostream:112: note: candidates are: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_ostream<_CharT, _Traits>& (*)(std::basic_ostream<_CharT, _Traits>&)) [with _CharT = char, _Traits = std::char_traits<char>]                  
    /usr/lib/gcc/x86_64-pc-linux-gnu/4.3.3/include/g++-v4/ostream:121: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_ios<_CharT, _Traits>& (*)(std::basic_ios<_CharT, _Traits>&)) [with _CharT = char, _Traits = std::char_traits<char>]                          
    /usr/lib/gcc/x86_64-pc-linux-gnu/4.3.3/include/g++-v4/ostream:131: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(std::ios_base& (*)(std::ios_base&)) [with _CharT = char, _Traits = std::char_traits<char>]                                                              
    /usr/lib/gcc/x86_64-pc-linux-gnu/4.3.3/include/g++-v4/ostream:169: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(long int) [with _CharT = char, _Traits = std::char_traits<char>]                                                                                        
    /usr/lib/gcc/x86_64-pc-linux-gnu/4.3.3/include/g++-v4/ostream:173: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(long unsigned int) [with _CharT = char, _Traits = std::char_traits<char>]                                                                               
    /usr/lib/gcc/x86_64-pc-linux-gnu/4.3.3/include/g++-v4/ostream:177: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(bool) [with _CharT = char, _Traits = std::char_traits<char>]                                                                                            
    /usr/lib/gcc/x86_64-pc-linux-gnu/4.3.3/include/g++-v4/bits/ostream.tcc:97: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(short int) [with _CharT = char, _Traits = std::char_traits<char>]
    /usr/lib/gcc/x86_64-pc-linux-gnu/4.3.3/include/g++-v4/ostream:184: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(short unsigned int) [with _CharT = char, _Traits = std::char_traits<char>]
    /usr/lib/gcc/x86_64-pc-linux-gnu/4.3.3/include/g++-v4/bits/ostream.tcc:111: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(int) [with _CharT = char, _Traits = std::char_traits<char>]
    /usr/lib/gcc/x86_64-pc-linux-gnu/4.3.3/include/g++-v4/ostream:195: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(unsigned int) [with _CharT = char, _Traits = std::char_traits<char>]
    /usr/lib/gcc/x86_64-pc-linux-gnu/4.3.3/include/g++-v4/ostream:204: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(long long int) [with _CharT = char, _Traits = std::char_traits<char>]
    /usr/lib/gcc/x86_64-pc-linux-gnu/4.3.3/include/g++-v4/ostream:208: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(long long unsigned int) [with _CharT = char, _Traits = std::char_traits<char>]
    /usr/lib/gcc/x86_64-pc-linux-gnu/4.3.3/include/g++-v4/ostream:213: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(double) [with _CharT = char, _Traits = std::char_traits<char>]
    /usr/lib/gcc/x86_64-pc-linux-gnu/4.3.3/include/g++-v4/ostream:217: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(float) [with _CharT = char, _Traits = std::char_traits<char>]
    /usr/lib/gcc/x86_64-pc-linux-gnu/4.3.3/include/g++-v4/ostream:225: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(long double) [with _CharT = char, _Traits = std::char_traits<char>]
    /usr/lib/gcc/x86_64-pc-linux-gnu/4.3.3/include/g++-v4/ostream:229: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(const void*) [with _CharT = char, _Traits = std::char_traits<char>]
    /usr/lib/gcc/x86_64-pc-linux-gnu/4.3.3/include/g++-v4/bits/ostream.tcc:125: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_streambuf<_CharT, _Traits>*) [with _CharT = char, _Traits = std::char_traits<char>]
    /usr/lib/gcc/x86_64-pc-linux-gnu/4.3.3/include/g++-v4/bits/basic_string.h:2421: note:                 std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, const std::basic_string<_CharT, _Traits, _Alloc>&) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>]
    

    Der Typ von AutoOut scheint nicht korrekt als std::ostringstream ermittelt werden zu können.
    Frag vllt. mal Google wie man std::iostreams korrekt ableitet (=engl. "inherit").



  • der_nub schrieb:

    ..., aber grundsaetzlich existiert das Problem, weil wchar_t oftmals nur ein typedef auf unsigned short oder aehnliches ist und damit der operator << (unsigned short*) aufgerufen wird,..

    Hallo der_nub,

    nein, es wird operator<<(void*) aufgerufen. Aber eben nur beim temporären Objekt.



  • Tut mir leid, für das "Pushen" des Threads, aber das Thema ist mir sehr wichtig.

    Hat womöglich noch jemand eine Idee, woran das lieegn könnte, wie man es ändern könnte oder Alternativen?

    Vielleicht nochmal zum Zweck des Ganzen:

    Der Code ist (prinzipiell) Bestandteil einiger Logging-Klassen, die ich in VC 6.0 geschrieben habe. Ich möchte damit die widerliche printf-Logging-Klasse, die wir hier haben, abschaffen. Doch gerade diese "modernere" Variante funktioniert beim neuen Compiler, der (hoffentlich) bald hier eingeführt wird, nicht mehr.. 😞

    Die Klasse AutoOut soll den zu loggenden Stream aufnehmen und als String an eine Logging-Klasse weitergeben.

    // statt:
    std::wostringstream logMsg;
    logMsg << ... // Nachricht zusammen stellen
    fileLogger.Log(logMsg.str());
    
    // soll sein:
    Log() << ... // Log() als inline Funktion, die AutoOut-Objekt zurück gibt
                 // AutoLog ruft dann bei der Destruktion fileLogger.Log(str()) auf
    


  • Ich würde Log gar nicht zu einer inline Funktion machen, sondern das ein beliebiges Objekt sein lassen, welches du als Singleton oder ein ähnliches System implementierst. Dann sollte das ganz gut gehen mit der Konstruktion und Destruktion.



  • drakon schrieb:

    Ich würde Log gar nicht zu einer inline Funktion machen, sondern das ein beliebiges Objekt sein lassen, welches du als Singleton oder ein ähnliches System implementierst. Dann sollte das ganz gut gehen mit der Konstruktion und Destruktion.

    Hallo drakon,

    meinst Du, ich soll eine Log-Klasse erstellen, die von std::wstringstream ableitetet ist oder die ein std::wstringstream-Objekt beinhaltet?

    Weil die Variante, in der ich direkt den Konstruktor von AutoOut aufrufe (statt über die inline-Funktion), das selbe Ergebnis liefert: unter VC6.0 geht es, unter VS2008 geht es nicht (operator<<(void*) wird aufgerufen).

    // identisches Resultat:
    
    AutoOut() << L"Hello World!";
    
    Log() << L"Hello World!";
    


  • Danke drakon, ich habe es jetzt so gelöst (ähnlich wie hier: http://www.c-plusplus.net/forum/viewtopic-var-t-is-244136.html).

    // Log.h:
    #include <sstream>
    #include <iostream>
    
    class Log{
    
          // Konstruktor/Destruktor //
       public:
          Log(){ }
    
          ~Log(){
              std::wcout << m_sstr.str() << std::endl;
          }
    
          // Memberfunktionen //
       public:
          template <typename T>
          std::ostream& operator<<(T& x){
             m_sstr << x;
             return m_sstr;
          }
    
          // Attribute //
       private:
          std::wstringstream m_sstr;
    }
    
    //main.cpp:
    #include "AutoOut.h"{
    
    int wmain(int argc, wchar_t* argv[]){
    
        Log() << L"Hello World!";
    }
    

Anmelden zum Antworten