[C/C++] const auf integrale typen in einer Funktion sinnvoll?
-
;fricky schrieb:
sie decken eine mögliche fehlerquelle auf, führen aber zwei oder drei neue ein. dieser effekt ist typisch für C++.
Jein. Sie zwingen den Programmierer dazu, darüber nachzudenken, was er eigentlich will. Er muss zwischen 4 casts wählen, die jeweils andere Hinweise geben:
const_cast wirft die Frage auf, ob ich das Objekt wirklich entconsten muss - wahrscheinlich ist es doch keine so gute Idee, darauf jetzt rumzuschreiben. Andererseits ist entconsten notwendig, wenn ich eine Klasse verwende, die const correctness nicht kennt(übrigens ist das der Grund, weswegen const_cast eingeführt wurde. Das Feature war schließlich nicht in Version 1 von C++ enthalten, deswegen gab es bereits eine Menge Code, die von dem Feature beeinflusst wurden. Und den musste man kompatibel machen).
reinterpret_cast lässt die Alarmglocken schrillen: was du da machst, ist potentiell Fehleranfällig und nicht portabel. Denk noch einmal drüber nach, was da passiert. Brauchst du es wirklich?
dynamic_cast sagt: okay, teste mal, ob das Ding diese Basisklasse ist. funktioniert natürlich nur bei polymorphen Typen, und darauf passt der Compiler auf. Also keine Gefahr. Oder doch: Auf 0 testen, oder Exception fangen. Nur für den Fall.
static_cast keine Gefahr, was da passiert schaltet normalerweise nur eine Warnung aus. Wenn was schief geht, meckert der Compiler rum.
C-Cast: ??? Potentiell gefährlich. Effekt nicht abschätzbar, ohne alles drum herum zu kennen.
-
fricky, glaub was du willst.
ich kann dich echt nicht mehr ernst nehmen.
geh uns spiel mit deinem C compiler.
-
Don06 schrieb:
Mit const_cast kann man auch volatile wegcasten. const_cast ist ein schlechter Name. Damit kann man cv-Qualifizierungen umwandeln.
Nur das entfernen von const benötigt allerdings einen const_cast. Alles andere (Hinzufügen von const; Hinzufügen/Entfernen von volatile) ist auch mit allen anderen cast-Formen möglich. Das ist auch unproblematisch: im Gegensatz zum Entfernen von const, bedeutet das Entfernen von volatile (sagen wir beim Funktionsaufruf) nicht die potentielle Verletzung einer Garantie beim Aufrufer.
-
camper schrieb:
Don06 schrieb:
Mit const_cast kann man auch volatile wegcasten. const_cast ist ein schlechter Name. Damit kann man cv-Qualifizierungen umwandeln.
Nur das entfernen von const benötigt allerdings einen const_cast. Alles andere (Hinzufügen von const; Hinzufügen/Entfernen von volatile) ist auch mit allen anderen cast-Formen möglich. Das ist auch unproblematisch: im Gegensatz zum Entfernen von const, bedeutet das Entfernen von volatile (sagen wir beim Funktionsaufruf) nicht die potentielle Verletzung einer Garantie beim Aufrufer.
hm.
bist du sicher?Comeau C/C++ 4.3.10.1 (Oct 6 2008 11:28:09) for ONLINE_EVALUATION_BETA2 Copyright 1988-2008 Comeau Computing. All rights reserved. MODE:strict errors C++ C++0x_extensions "ComeauTest.c", line 4: error: static_cast cannot cast away const or other type qualifiers int* p = static_cast<int*>(&i); ^ 1 error detected in the compilation of "ComeauTest.c".
p.S.: hab "i" natürlich volatile gemacht, und nicht const.
-
@otze: klingt sehr einleuchtend was du sagst. ich, in meiner eigenschaft als radikaler c++-hasser, muss jetzt zwar einwenden, dass es sich bei diesen vielen verschiedenen casts offensichtlich um einen konzeptuellen fehler in C++ handelt (welche andere programmiersprache braucht sowas noch?), aber gut, das ist wohl nun mal so.
camper schrieb:
Das ist auch unproblematisch: im Gegensatz zum Entfernen von const, bedeutet das Entfernen von volatile (sagen wir beim Funktionsaufruf) nicht die potentielle Verletzung einer Garantie beim Aufrufer.
begründung?
wenn du volatile von z.b. einem pointer wegmachst, der ursprünglich volatile deklariert wurde, haste auch undefiniertes verhalten (wie bei const): https://www.securecoding.cert.org/confluence/display/seccode/EXP32-C.+Do+not+access+a+volatile+object+through+a+non-volatile+reference
oder gehört du auch zu den leuten, die 'volatile' für sinnlos halten?
-
;fricky schrieb:
@otze: klingt sehr einleuchtend was du sagst. ich, in meiner eigenschaft als radikaler c++-hasser, muss jetzt zwar einwenden, dass es sich bei diesen vielen verschiedenen casts offensichtlich um einen konzeptuellen fehler in C++ handelt (welche andere programmiersprache braucht sowas noch?), aber gut, das ist wohl nun mal so.
Brauchen tut man garnix. Mach C Casts wenn du dumm sein willst. Es ist eine Hilfe die kluge Leute annehmen. Brauchen tut man das nicht, aber braucht man wirklich streng typisierte Sprachen? Oder braucht man Hochsprachen?
Kluge Leute verwenden die Tools die man ihnen gibt um die qualität oder produktivität der Arbeit zu steigern. Die C++ casts erhöhen die qualität des Codes.
-
Shade Of Mine schrieb:
Mach C Casts wenn du dumm sein willst.
besser noch: meide einfach programmiersprachen, die fünf verschiedene casts brauchen. dann stellt sich die frage garnicht erst, ob du dumm oder schlau sein willst.
-
;fricky schrieb:
Shade Of Mine schrieb:
Mach C Casts wenn du dumm sein willst.
besser noch: meide einfach programmiersprachen, die fünf verschiedene casts brauchen. dann stellt sich die frage garnicht erst, ob du dumm oder schlau sein willst.
fricky, dich will in der C++ welt sowieso keiner. bleib bei C. lass uns in ruhe.
-
;fricky schrieb:
Shade Of Mine schrieb:
Mach C Casts wenn du dumm sein willst.
besser noch: meide einfach programmiersprachen, die fünf verschiedene casts brauchen. dann stellt sich die frage garnicht erst, ob du dumm oder schlau sein willst.
Du brauchst die Casts nicht, genauso wie du beim Autofahren keine Sicherheitsgurte brauchst oder Vekehrszeichen kennen musst. Kluge Leute tun sich aber anschnallen und auf Vekehrszeichen achten
-
Shade Of Mine schrieb:
Du brauchst die Casts nicht, genauso wie du beim Autofahren keine Sicherheitsgurte brauchst oder Vekehrszeichen kennen musst. Kluge Leute tun sich aber anschnallen und auf Vekehrszeichen achten
unpassender vergleich. *confused*
kluge leute fahren vorausschauend und situationsangemessen, dazu gehört ein wenig fahrpraxis. anschnallen und auf verkehrszeichen achten macht jeder fahrschüler bereits in der ersten stunde.
-
Shade Of Mine schrieb:
Die C++ casts erhöhen die qualität des Codes.
C++ kennt doch Exceptions, oder? Wieso wurde nicht einfach vollgendes gemacht:
try { Foo* foo = (foo*)something; } catch (ConstCastException e) { // cannot cast const * something to Foo* } catch (PolymorphCastException e) { // cannot cast from something to Foo* } Foo foo = (Foo) something; // ist wie static_cast: Wenn was schief geht, meckert der Compiler rum. Foo* foo = (foo*)something; // ist wie reinterpret_cast, entweder es wird eine der 2 Exceptions geworfen oder es gibt wie // bei reinterpret_cast undifiniertes Verhalten.
Keine 4 casts-Typen und kombatibel zu allen C++ Code, dass die C-Style casts kennt und Exceptions kann.
-
hustbaer schrieb:
hm.
bist du sicher?nein. hab unfug geschrieben.
-
DEvent schrieb:
C++ kennt doch Exceptions, oder? Wieso wurde nicht einfach vollgendes gemacht:
dynamic_cast macht btw. genau das. es wirft ne exception wenn der cast fehlschlägt. und warum statische casts nix werfen sollte eigentlich klar sein.
unterschiedliche sachen die unterschiedliche arbeit machen und unterschiedliche auswirkungen haben sehen halt unterschiedlich aus.
was ist zB bei
T* t=(T*)f;
absolut mehrdeutig solange du nicht genau weisst was f ist...
-
Shade Of Mine schrieb:
DEvent schrieb:
C++ kennt doch Exceptions, oder? Wieso wurde nicht einfach vollgendes gemacht:
dynamic_cast macht btw. genau das. es wirft ne exception wenn der cast fehlschlägt.
nicht bei pointern, da gibt er einfach 0 zurück, wenn es fehlschlägt. warum dieses unterschiedliche verhalten? könnte er nicht in beiden fällen eine exception werfen?
-
;fricky schrieb:
nicht bei pointern, da gibt er einfach 0 zurück, wenn es fehlschlägt. warum dieses unterschiedliche verhalten? könnte er nicht in beiden fällen eine exception werfen?
Exceptions nur in ausnahmefällen.
Und jetzt denk mal an die möglichen Anwendungen für dynamic_cast. Dann wirst du sehen dass es meistens zum testen verwendet wird ob eine bestimmte beziehung zwischen dem objekt und einer klasse besteht.Wenn du dich ein bisschen mit der Materie befassen würdest, wüsstest du sowas.
-
Shade Of Mine schrieb:
;fricky schrieb:
nicht bei pointern, da gibt er einfach 0 zurück, wenn es fehlschlägt. warum dieses unterschiedliche verhalten? könnte er nicht in beiden fällen eine exception werfen?
Exceptions nur in ausnahmefällen.
Und jetzt denk mal an die möglichen Anwendungen für dynamic_cast. Dann wirst du sehen dass es meistens zum testen verwendet wird ob eine bestimmte beziehung zwischen dem objekt und einer klasse besteht.Wenn du dich ein bisschen mit der Materie befassen würdest, wüsstest du sowas.
Andere Sprachen haben ein instance_of.
Wenn ein Cast einfach eine exception werfen wuerde, so koennte man sich diese xxx_cast sparen und alle Casts haetten ein konsistentes Verhalten.
-
Shade Of Mine schrieb:
Exceptions nur in ausnahmefällen.
man hört immer, exceptions werden in c++ dem prüfen von rückgabewerten vorgezogen. wieso plötzlich diese ausnahme, dass beim dynamic-cast, auf pointer angewendet, der rückgabewert getestet werden muss?
Shade Of Mine schrieb:
Und jetzt denk mal an die möglichen Anwendungen für dynamic_cast. Dann wirst du sehen dass es meistens zum testen verwendet wird ob eine bestimmte beziehung zwischen dem objekt und einer klasse besteht.
hat c++ nicht 'typeid' um sowas zu testen?
-
;fricky schrieb:
Shade Of Mine schrieb:
Exceptions nur in ausnahmefällen.
man hört immer, exceptions werden in c++ dem prüfen von rückgabewerten vorgezogen. wieso plötzlich diese ausnahme, dass beim dynamic-cast, auf pointer angewendet, der rückgabewert getestet werden muss?
hören ist gut, zuhören solltest du auch noch.
;fricky schrieb:
Shade Of Mine schrieb:
Und jetzt denk mal an die möglichen Anwendungen für dynamic_cast. Dann wirst du sehen dass es meistens zum testen verwendet wird ob eine bestimmte beziehung zwischen dem objekt und einer klasse besteht.
hat c++ nicht 'typeid' um sowas zu testen?
[/quote]nein. typeid gibt Informationen über den am weitesten abgeleiteten Typ, der interessiert in cross-cast-Fällen überhaupt nicht.
-
DEvent schrieb:
Andere Sprachen haben ein instance_of.
Genau darauf habe ich gewartet.
Es zeigt nämlich wunderschön dass hier im Kreis argumentiert wird.In C++ gibt es eben kein instanceof sondern nur einen dynamic_cast der eben testet ob a eine instanz von b oder von einer von b abgeleiteten klasse ist.
Wenn es einen instanceof operator geben würde, hätten wir hier die exakt selbe diskussion nur dass eine vereinheitlichung gefordert werden würde, weil ja dynamic_cast schon diese Aufgabe erfüllt.
Man kann sich nicht immer alles zurecht drehen: erst ist vielfalt schlecht, dann ist sie wieder gut, dann ist redundanz besser und dann ist sie wieder schlecht.
Wenn ein Cast einfach eine exception werfen wuerde, so koennte man sich diese xxx_cast sparen und alle Casts haetten ein konsistentes Verhalten.
Es gibt nur einen cast der eine exception werfen kann: dynamic_cast. Denn alle anderen cast arten sind zur Compile Zeit validierbar. Es macht keinen Sinn dass ein static_cast oder const_cast oder reinterpret_cast eine exception wirft.
Und der einzige cast wo es sinn machen kann, wirft genau dann eine exception wenn es sinn macht (und wenn es keinen sinn macht, dann wirft er keine). Und damit ist eine konsistenz zwischen allen casts nicht mehr realisierbar.
Das ist ziemlich ideal.
Man muss ja nurmal an Java denken:
if(!(o instanceof Foo)) return false; Foo bar = (Foo) o;
versus
bar = dynamic_cast<Foo*>(o); if(!bar) return false;
Ich habe hier enorm das Gefühl dass einfach nur Mainstream Techniken promoted werden und alles andere ist schlecht. Ob ich jetzt instanceof oder dynamic_cast mache ist komplett egal. Ich könnte auch ein hühott() machen, namen sind schall und rauch.
Die C++ casts dagegen bieten eben vorallem im Vergleich zu Java einen enormen Vorteil: sie sind mächtiger.
Denn Java bietet im Prinzip nur eine mischung aus static_cast und dynamic_cast an. Einen const_cast braucht java nicht, da es keine const-correctness gibt und man dort statt const eben clone() verwendet (und clone kann man nicht rückgängig machen). Einen reinterpret_cast hat Java nicht und auch nichts vergleichbares. Ergo gibt es in Java ja nur dynamic_cast und static_cast. Und da man in Java nicht sagen kann "vertrau mir, ich weiss was ich tue" ist ein static_cast ziemlich unnötig.
Denn ein static_cast kann für up und downcasts verwendet werden (einzig für cross casts nicht). Und es spart die lookups in der vtable. Diese Möglichkeit gibt es in Java nicht (design entscheidung), ergo ist static_cast auf primitive typen limitiert und dynamic_cast auf referenzen. Somit ist jeder cast aus dem kontext heraus immer eindeutig und es gibt keinen grund einen anderen cast zu verwenden.
C++ ist komplexer. Deshalb verwendet man ja in C++ auch checked_casts statt dynamic_casts wenn es um up/down casts geht. ein checked_cast ist ein static_cast der in der debug version dynamic_cast verwendet um den cast zu validieren. Ist wunderschön schnell und man braucht keine vtable lookups.
Die Wahl zu haben ist immer etwas gutes. Es ist nicht immer das einfachste und C++ ist sicher nicht die simpelste Sprache der Welt, aber C++ bietet dem Programmierer eben Power Tools. Die unterschiedlichen Casts sind eben solche Tools die trivial zu meistern sind und uU relevante Vorteile bieten. Meistens erhöhen sie nur die Lesbarkeit des Codes, aber in gewissen Situationen sind sie eben unersetzbar.
Aber wie gesagt: brauchen tut C++ diese Casts nicht. C Casts würden reichen wenn man ihnen die dynamic_cast Fähigkeit gegeben hätte (hat man nicht getan da C Casts böse sind).
-
Und wer die Casts überhaupt nicht mag, kann immer noch auf Assembler seiner Wahl umsteigen. Dort hat man nur die CPU Register und die ganzen Rohdaten, die vorzeichenlos oder vorzeichenbehaftet oder gar eine Adresse sein können, je nach dem, wie man gerade Lust hat, sie zu interpretieren und man darf alles ineinander, übereinander, durcheinander kopieren, verschieben, zuweisen und was weiss ich noch damit anstellen, alles ohne Casts, daher Assembler eben