static_cast thread safe?



  • Hi,
    ich bin eben in eine Diskussion geraten und zwar ging es darum ob ein static_cast thread safe ist. Ich lese grade das Buch "Der C++ Programmierer" und bin dort auf diesen gestoßen. Allerdings hab ich vorher immer ein c-cast benutzt. Im Buch wird nun empfohlen den static_cast zu benutzen ich also mal nachgefragt und es wurde mir gesagt das static_cast nicht thread safe ist.

    Vielleicht könntet ihr mir dazu noch mal sagen wie der cast abläuft. Für mich ist das C++ syntax die dem Compiler sagt das er eine Typumwandlung machen muss. Richtig?

    Vielen dank schon mal



  • Es sind beide nicht per se threadsafe. Aber immer, wenn static_cast nicht threadsafe ist, ist auch der C-Cast nicht threadsafe.

    struct strange {
      operator int() {
        return !(std::cout << "Diese Operation ist nicht threadsafe!" << std::endl);
      }
    };
    
    int main()
    {
      strange s;
      static_cast<int>(s);
      (int)s;
    }
    

    Ich habe allerdings das Gefühl, dass da ein grundlegendes Verständnisproblem von Casts und Threading herrscht. Lies mal das durch, dann siehst du, was ein Cast ist.

    reinterpret_cast ist immer Threadsafe.



  • Cast ist ein Synonym für explizite Typkonvertierung . Das brauchst du, wenn der Compiler

    1. schlicht nicht in der Lage ist, eine implizite Typkonvertierung durchzuführen.

    int main()
    {
    	int x = 0;
    	const int& cref = x;
    	int& ref = cref; // Er kann nicht implizit konvertieren. [const_cast ist hier ok, da kein const auf höchster Ebene]
    }
    

    2. sich nicht entscheiden kann, zu welchem Typ er konvertieren soll.

    void fkt( float f )
    {
    }
    void fkt( double d )
    {
    }
    int main()
    {
    	fkt( 2 ); // Er kann sich nicht entscheiden.
    }
    

    3. dir eine Warnung gibt, die du gelesen, verstanden und beseitigen möchtest, da es in deinem Fall zu keinem Schaden kommt.

    int main()
    {
    	unsigned x = 8;
    	unsigned char uc = x; // Warnung: Eventuell gibt es einen Informationsverlust.
    }
    

    Wie in dem Buch richtig stehst, sollst du C++-Cast-Operatoren verwenden,

    1. da sie Typsicherheit bieten, d.h. Fehler können zur Kompilierzeit abgefangen werden. (Du kannst z.B. nicht aus Versehen const wegcasten)

    2. die anschauliche Syntax dir sagt, was passiert. (beispielsweise sagt dir const_cast, dass das const verschwindet). Ein C-Cast sagt dir das nicht. Bei einem C-Cast kann alles mögliche passieren, z.B. kann gleichzeitg static_cast + const_cast passieren.

    3. die anschauliche Syntax dir ermöglicht, den Quellcode nach Casts zu durchsuchen. Suche nach "_cast".

    Auch wenn es die guten C++-Cast-Operatoren gibt, solltest du sparsam damit umgehen. Bzw. const_cast , dynamic_cast und reinterpret_cast sollten sowieso so gut wie nie vorkommen.

    1. Wenn du dynamic_cast brauchst, hast du höchst wahrscheinlich einen Designfehler gemacht. Salopp gesagt: Kein Designfehler --> Kein dynamic_cast nötig.

    2. Willst const_cast verwenden, solltest du dich fragen, wieso du das willst. Manche leute verwenden es, um Compilerfehler zu beseitigen. Dass das nicht Sinn und Zweck ist und außerdem sau gefährlich ist, sollte klar sein. const_cast darfst du nur dann verwenden, wenn es auf höchster Ebene kein const gibt. Ansonsten hast du UB.

    1. reinterpret_cast ist sau gefährlich. Da musst du schon genau wissen, was du sonst, ansonsten landest du schnell bei UB.


  • Vor allem ist reinterpret_cast meistens nichtmal platformunabhängig.

    Ich selbst kenne einen Anwendungsfall für const_cast, den erklärt Scott Meyers in seinem Buch "Effective C++". Sehr interessant zu lesen.


  • Mod

    Fuchs aus dem Wald schrieb:

    Hi,
    ich bin eben in eine Diskussion geraten und zwar ging es darum ob ein static_cast thread safe ist. Ich lese grade das Buch "Der C++ Programmierer" und bin dort auf diesen gestoßen. Allerdings hab ich vorher immer ein c-cast benutzt. Im Buch wird nun empfohlen den static_cast zu benutzen ich also mal nachgefragt und es wurde mir gesagt das static_cast nicht thread safe ist.

    Eine sinnlose Behauptung, wenn sie nicht erläutert wird. Threadsicherheit ist auch keine Funktion der Form eines Ausdrucks.



  • Vielen Dank für eure Informationen! Das war sehr lehrreich! Im Buch wurde das bis jetzt noch nicht genauer erklärt denke das wird aber noch kommen. EDIT: Jo kommt unter 7.9 🙂
    Der link und die Erklärung von out waren super. Das von Scott Meyers hab ich über google auch schon mal gefunden aber leider nicht lesen können. Müsste ja das Buch haben. 😃



  • Fuchs aus dem Wald schrieb:

    Der link und die Erklärung von out waren super. Das von Scott Meyers hab ich über google auch schon mal gefunden aber leider nicht lesen können. Müsste ja das Buch haben. 😃

    Ungefähr so:

    class Klasse
    {
        const object& foo() const
        {
            // ...
        }
    
        object& foo()
        {
            // Nutze Klasse::foo() const
            return const_cast<object&>(const_cast<const Klasse*>(this)->foo());
        }
    };
    

    Man spart sich eine Implementierung, allerdings halte ich es in den meisten Fällen für angebracht, einen anderen weg zu suchen.



  • Der innere const_cast sollte ein static_cast sein.

    reinterpret_cast ist super nuetzlich zur Serialisierung. Davon grundsaetzlich abzuraten halte ich fuer Mist.



  • reinterpret_cast ist super nützlich zur platformabhängigen, compilerversionabhängigen und compilereinstellungsabhängigen Serialisierung.



  • ftfy schrieb:

    reinterpret_cast ist super nützlich zur platformabhängigen, compilerversionabhängigen und compilereinstellungsabhängigen Serialisierung.

    Ich finde es toll, dass du Code schreibst, der auf jedem noch so besonderen Mikrocontroller mit C++-Implementierung laeuft. Das ist mir bei meinen Programmen aber relativ egal.

    Auf meinen Ziel-Plattformen ist:
    - ein (u)intN_t genau N Bytes gross, in little-endian gespeichert und falls signed im 2er Komplement
    - ein float/double in einem IEEE754-konformen Format

    Ausserdem ist reinterpret_cast flott. Mag sein, dass der Compiler das optimieren kann, wenn ich Bitoperationen verwende. Spaetestens bei Fliesskommazahlen wirds dann aber schwer. Flotter als reinterpret_cast gehts wohl kaum. Zumal das genau das ausdrueckt, was ich tun moechte: "Gib mir die Bytes von diesem Ding."

    Daher:

    Kellerautomat schrieb:

    Davon grundsaetzlich abzuraten halte ich fuer Mist.

    Auf deinen sinnlosen Rechtschreibflame gehe ich mal nicht ein.



  • Mal nochmal für mich: static_cast für native Typen ist eine Uminterpretation eines Wertes und kostet somit keine Laufzeit und ist somit immer threadsafe?



  • Eisflamme schrieb:

    Mal nochmal für mich: static_cast für native Typen ist eine Uminterpretation eines Wertes und kostet somit keine Laufzeit und ist somit immer threadsafe?

    Nein.
    Bei double -> int muss gerechnet werden, weil die Bitinterpretation anders ist.
    Ebenso int -> long, weil die oberen Bits genullt sein müssen.
    float -> double ebenfalls.
    signed -> unsigned hingegen nicht (Zweierkomplement vorausgesetzt)

    Kostet aber nur minimal Laufzeit.

    Threadsafe hat gar nichts damit zu tun. Schon das Lesen einer int-Variable ist nicht threadsafe (atomar)



  • Habe gerade überlegt, wieso das dann nichts damit zu tun hat. Da fiel mir ein, dass man den Wert ja auch irgendwo benutzen muss, weil der Cast sonst sinnlos ist. Alles klar 🙂



  • Eisflamme schrieb:

    Habe gerade überlegt, wieso das dann nichts damit zu tun hat. Da fiel mir ein, dass man den Wert ja auch irgendwo benutzen muss, weil der Cast sonst sinnlos ist. Alles klar 🙂

    Wow genau dieser Satz wird hier Augen öffnen. 😃
    Danke an die vielen Antworten! Hat mich weiter gebracht. 🙂



  • eehnope schrieb:

    Eisflamme schrieb:

    Mal nochmal für mich: static_cast für native Typen ist eine Uminterpretation eines Wertes und kostet somit keine Laufzeit und ist somit immer threadsafe?

    Nein.
    Bei double -> int muss gerechnet werden, weil die Bitinterpretation anders ist.
    Ebenso int -> long, weil die oberen Bits genullt sein müssen.
    float -> double ebenfalls.
    signed -> unsigned hingegen nicht (Zweierkomplement vorausgesetzt)

    Kostet aber nur minimal Laufzeit.

    Ich denke, in vielen Fällen kostet es sogar keine Laufzeitdifferenz, denn x87 FPUs haben 80bit große Register.
    Bei double->int muss in ein Integer, beim Speichern in einer double-Variable muss von 80 bit auf 64 umgerechnet werden (FIST statt FST).
    Oft wird der Geschwindigkeitsverlust sogar unter einem Takt liegen, eine Differenz auf die man selbst bei starker Optimierung verzichten kann.



  • Ich verwende reinterpret_cast für 2 Anwendungsfälle:

    1. Bei meinen Gamehacks:

    uintptr_t const IS_SWIMMING_ADDRESS = 0xDEADBEEF;
    *reinrterpret_cast<uint32_t>(IS_SWIMMING_ADDRESS) = true;
    

    2. mit std::aligned_storage



  • Ethon schrieb:

    mit std::aligned_storage

    static_cast ?



  • Sone schrieb:

    Ethon schrieb:

    mit std::aligned_storage

    static_cast ?

    static_cast<Foo*>(static_cast<void*>(bar));
    

    Finde ich nicht wirklich besser. 😞



  • Ethon schrieb:

    static_cast<Foo*>(static_cast<void*>(bar));
    

    Missverständnis.


Log in to reply