boost:::variant<> fuer C++/CLI .NET? (oder sowas in der Art)



  • Jochen Kalmbach schrieb:

    Ben04 schrieb:

    Geht mit ganz normalem C++ auch. Siehe boost::any.

    Aber nichts *zwangsweise*. Sondern nur wenn jeder Programmierer sich auch daran hält...

    boost::any geht mit jedem Typen, der einen Kopierkonstruktor hat.



  • Der *größte* Unterschied zu normalem C++ ist die Typsicherheit, was auch bedeutet: Du kannst zwar in Deinem Source-Code casten wie Du willst. Zur Laufzeit wird aber *sichergestellt* das der cast auch geht! Sonst wird eine Exception geworfen!

    Also ein

    ref class A{};
    ref class B{};
    

    kannst Du zwar beides in ein "Object" reintun, aber das zurückcasten geht eben nur, wenn es zur Laufzeit auch als "ok" akzeptiert ist:

    Object^ a = gcnew A();
    Object^ b = gcnew B();
    A ^aa = (A^) b;
    B ^bb = (B^) a;
    

    Lässt sich wunderbar compilieren, wird zur Laufzeit aber eine Exception werfen.

    In normalem C++ dagegen wirft dies auch zur Laufzeit keine Exception, sondern Dein Code macht halt irgendwas damit und solche Dinge führen meistens zu abstürzen und sind auch schwer zu finden (natürlich nicht in diesem trivialen Beispiel)...



  • Jochen Kalmbach schrieb:

    Der *größte* Unterschied zu normalem C++ ist die Typsicherheit, was auch bedeutet: Du kannst zwar in Deinem Source-Code casten wie Du willst. Zur Laufzeit wird aber *sichergestellt* das der cast auch geht! Sonst wird eine Exception geworfen!

    Also ein

    ref class A{};
    ref class B{};
    

    kannst Du zwar beides in ein "Object" reintun, aber das zurückcasten geht eben nur, wenn es zur Laufzeit auch als "ok" akzeptiert ist:

    Object^ a = gcnew A();
    Object^ b = gcnew B();
    A ^aa = (A^) b;
    B ^bb = (B^) a;
    

    Lässt sich wunderbar compilieren, wird zur Laufzeit aber eine Exception werfen.

    In normalem C++ dagegen wirft dies auch zur Laufzeit keine Exception, sondern Dein Code macht halt irgendwas damit und solche Dinge führen meistens zu abstürzen und sind auch schwer zu finden (natürlich nicht in diesem trivialen Beispiel)...

    Klingt irgendwie nach dynamic_cast. Das wirft nämlich auch ne Exception...

    Natürlich braucht man dazu eine gemeinsame Basisklasse, aber das ist doch nur gut.

    Grundsätzlich bevorzuge ich es, Fehler zur Compilezeit vor die Nase geworfen zu bekommen. Da gibt es dann wesentlich bessere Sprachen als C++ und C++/CLI, aber irgendwie bleib ich immer bei C++ hängen. 😃



  • Jochen Kalmbach schrieb:

    Der *größte* Unterschied zu normalem C++ ist die Typsicherheit, was auch bedeutet: Du kannst zwar in Deinem Source-Code casten wie Du willst. Zur Laufzeit wird aber *sichergestellt* das der cast auch geht! Sonst wird eine Exception geworfen!

    Hättest du dir die Dokumentation von boost::any angeschaut (etwa 4 lesbar formatierte Seiten inklusive Reference) wüsstest du, dass dies auch mit boost::any möglich ist. Wird ein Zeiger auf any gecastetet so wird der richtige Wert oder NULL zurückgegeben. Bei Referencen wird im Fehlerfall boost::bad_any_cast geworfen. Einen ungeprüften downcast eines boost::any ist nur durch hacken möglich.

    boost::variant bietet zwar ähnliche Methoden an jedoch wird hier empfohlen immer mit Visitoren zu arbeiten anstatt eines Downcasts. (Das ist auch wesentlich sicherer!)

    Jochen Kalmbach schrieb:

    Der *größte* Unterschied zu normalem C++ ist die Typsicherheit, was auch bedeutet: Du kannst zwar in Deinem Source-Code casten wie Du willst. Zur Laufzeit wird aber *sichergestellt* das der cast auch geht! Sonst wird eine Exception geworfen!

    Dies ist keine Erfindung von C++/CIL sondern ist schon seit schon über gut einem Jahrzehnt bei jedem C++ Compiler unter dem Namen dynamic_cast dabei.

    Sowieso finde ich, dass du ein komisches Verständnis von Sicherheit hast.

    • Beim einem native Programm kommt es zu einer Zugriffsverletzung in Folge eines falschen ungeschützten Casts, das Betriebssystem greift ein und beendet das Programm. Bei den meisten Betriebssystemen kann das Programm Veto einlegen und den Fehler behandeln, bei Windows durch ein Ausnahmesystem. Wie dies geht ist irrelevant da man eh Programmierungsfehler nicht zur Laufzeit behandeln kann.
    • Beim einem .net Programm kommt es zu einer einer Exception wegen eines falschen Casts. Das Programm fängt sie nicht ab das es sich nicht selbst patchen kann. Danach beendet die .NET Runtime das Programm aufgrund einer ungefangen Ausnahme.

    Das Resultat ist also genau das gleiche, egal ob .NET oder native. Gleiches Resultat ist in meinen Augen gleiche Sicherheit.



  • Wäre es nicht geil, wenn man sich das ganze rumcasten sparen könnte und das per Pattern Matching erledigen könnte?



  • Beim einem .net Programm kommt es zu einer einer Exception wegen eines falschen Casts. Das Programm fängt sie nicht ab das es sich nicht selbst patchen kann. Danach beendet die .NET Runtime das Programm aufgrund einer ungefangen Ausnahme.

    http://www.c-plusplus.net/forum/viewtopic-var-t-is-171928.html



  • [edit] total am Thema vorbei [/edit]



  • Ben04 schrieb:

    Hättest du dir die Dokumentation von boost::any angeschaut (etwa 4 lesbar formatierte Seiten inklusive Reference) wüsstest du, dass dies auch mit boost::any möglich ist.

    Hab ich doch nie abgestritten... Aber: Du kannst dann trotzdem noch wild casten wie Du willst ohne dass es jemand prüft! boost::any ist nix in der Sprache oder dem Compiler eingebautes Feature! Das ist der entscheidende Unterschied...



  • Jochen Kalmbach schrieb:

    Aber: Du kannst dann trotzdem noch wild casten wie Du willst ohne dass es jemand prüft!

    Blödsinn. Wie soll das gehen? Man kann auf boost::any nur mit den any_cast-Funktionen zugreifen. Und die sind so sicher wie dynamic_cast, also sehr.



  • (some_type*) any_var; !? bzw. static_cast !?



  • Knuddlbaer schrieb:

    Beim einem .net Programm kommt es zu einer einer Exception wegen eines falschen Casts. Das Programm fängt sie nicht ab das es sich nicht selbst patchen kann. Danach beendet die .NET Runtime das Programm aufgrund einer ungefangen Ausnahme.

    http://www.c-plusplus.net/forum/viewtopic-var-t-is-171928.html

    http://msdn2.microsoft.com/en-us/library/ms680634.aspx
    SetUnhandledExceptionFilter

    Kann man also genau so gut in einem native Programmen machen. Der Grund warum der Standard da nichts vorschreibt ist ganz einfach : Diese Funktion ist sinnlos.

    Helium schrieb:

    Wäre es nicht geil, wenn man sich das ganze rumcasten sparen könnte und das per Pattern Matching erledigen könnte?

    Hängt von der Situation ab, allerdings von Zeit zu Zeit wäre das wirklich geil. boost::variant ist da recht flexibel solange es nur um den statischen Type geht.

    (some_type*) any_var; !? bzw. static_cast !?

    Geht vielleicht wenn der Compiler ganz lieb ist aber eher nicht. static_cast darf nicht gehen. Mit C-Casts aber zu begründen, dass eine Sprache unsicher ist, ist aber auch schon sehr schwach. Man muss sich ja nur sehr wenig vertippen und schon wurde

    boost::any_cast<Derived*>(&my_any)
    

    zu

    (Derived*)my_any
    

    Unwissentlich nutzt man C-Casts nicht.



  • Jochen Kalmbach schrieb:

    (some_type*) any_var; !? bzw. static_cast !?

    Das geht nicht. Meckert der Compiler an.

    boost::any x,y;
    x=4;
    y=4.2;
    int a = boost::any_cast<int>(x);//geht
    int a1 = boost::any_cast<int>(y);//wirft eine exception
    int b = *(int*)x;//geht nicht
    int c = *(int*)&x;//compiliert, wird aber garbage ergeben
    

    boost::any ist absolut sicher.



  • Wir wollen nicht diskutieren, wie sicher oder unsicher boost::any ist, sondern ein boost::variant-equivalent nachbauen.



  • Helium schrieb:

    Wir wollen nicht diskutieren, wie sicher oder unsicher boost::any ist, sondern ein boost::variant-equivalent nachbauen.

    Wozu? Man kann boost::variant und boost::any doch auch unter C++/CLI verwenden?!


Anmelden zum Antworten