Komischer Effekt bei impliziter vs. expliziter Konvertierung in char const*



  • Mir ist eben etwas total komisches aufgefallen. Ich habe eine Klasse, die so ähnlich aussieht wie.

    class MyClass
    {
      std::string str;
    
    public:
      MyClass(char const* cstr) : str(cstr) {}
    
      operator char const*() const{
        return str.c_str();
      }
      char const* operator *() const{
        return str.c_str();
      }
    };
    

    Nun will ich das in einen Stream ausgeben...

    MyClass s("something");
    
    std::cout << *s << std::endl; // gibt den String aus
    std::cout << s << std::endl;  // gibt die Adresse aus
    char const* cs = s;
    std::cout << cs << std::endl; // gibt wieder den String aus
    

    Was mich wundert: Der Rückgabetyp von operator* und operator char const* ist gleich. Warum ist die Ausgabe anders? Viel schlimmer, warum funktioniert es, wenn ich es erst an einen temporären Pointer zuweise? Mein aktueller Compiler ist VC++11.

    Ich habe erst gedacht es ist halt so, dass die Streams Pointer ausgeben. Aber warum funktioniert es mal und mal nicht? Vor allem, wenn ich std::cout << "Hello World" mache, dann ist der Typ von dem temporären String ja auch char const*, oder nicht?

    Jemand eine Idee? Bin grad echt dabei an mir zu zweifeln.



  • Ich vermute fast das ist ein Bug. Zumindest sind sich gcc 4.4, gcc 4.9, clang 3.6 und die neueste VC Version einig, dass in allen Fällen der String ausgegeben wird. Wenn ich nacher zuhause bin kann ich nochmal ältere VC Versionen testen.



  • Hallo goi,

    scheint ein VC++11-Bug zu sein. Korrekt wäre es, wenn in jedem Fall der Text ausgegeben würde. Der VC++12 macht das auch.

    BTW: solche impliziten Konvertierungen sollte man vermeiden. Also besser:

    class MyClass
    {
      std::string str;
    
    public:
      MyClass(char const* cstr) : str(cstr) {}
    
      explicit operator char const*() const{ // explicit
        return str.c_str();
      } 
    // usw.
    

    und später dann:

    cout << " s : " <<  static_cast< const char* >( s ) << endl;
    

    .. keine Ahnung, ob der VC++11 das 'explicit operator' beherrscht.

    Gruß
    Werner



  • Also das mit dem static_cast wäre mir zuviel Tipparbeit. Da würde ich mir lieber eine Memberfunktion oder so definieren.

    Nochmal zu dem eigentlichen Problem: Ich kann den Fehler weder mit VS2010, VS2013 noch mit VS2015 nachvollziehen. Die vom TO verwendete Version VS2012 habe ich gerade natürlich nicht installiert...



  • Nachtrag: Ich hab mir jetzt extra VS2012 installiert und damit kann ich den Fehler auch nicht reproduzieren. Welcher Compiler Version und Einstellungen benutzt du genau? Und dein Beispiel ist sicher auch komplett? Nicht das du zum Posten hier irgendwas aus deiner Klasse gelöscht hast was für den Fehler verantwortlich war.



  • Ups, was ich vielleicht noch dazu sagen sollte: Das passiert über DLL-Grenzen hinweg, also ich lege das Objekt in einer DLL an und will den String außerhalb lesen (und dabei nicht std::string über die DLL-Grenze schicken), deswegen ist es nicht sonderlich praktikabel hier ein minimales Beispiel zu posten. Die Klasse an sich ist tatsächlich so einfach und die DLL ist mit gleichen Settings wie die Executable kompiliert.

    @Werner: Das mit dem explicit versuche ich mal gleich. So kann ich zumindest unerwünschtes Verhalten abschalten falls ich schon das Problem nicht beseitigt bekomme.



  • goi schrieb:

    Das passiert über DLL-Grenzen hinweg

    Wäre mir neu, dass DLLs irgendwas an der Overload Resolution von C++ ändern.



  • Ja, es ist irgendwie wie verhext. Ich schaue mal, dass ich es auf etwas minimales reduziert bekomme. In meinem Fall ist es auch nicht std::cout sondern ein std::wostringstream, aber ich denke nicht, dass das das Problem ist.


Log in to reply