In C++ sieht man ja oft solche Mehrfachzuweisungen:
1
counter=flankenerkennung=entprellen=taster;
Unter C ist die Bedeutung eindeutig, alle Variablen werden auf den
gleichen Wert gesetzt.
Unter C++ ist die Bedeutung aber eine völlig andere. Wo kann man
nachlesen, was das bedeutet?
Peter D. schrieb:> In C++ sieht man ja oft solche Mehrfachzuweisungen:counter => flankenerkennung = entprellen = taster;> Unter C ist die Bedeutung eindeutig, alle Variablen werden auf den> gleichen Wert gesetzt.
Nein, dass ist nicht der fall.
1
flankenerkennung=entprellen=taster;
entspricht:
1
entprellen=taster;
2
flankenerkennung=entprellen;
Insbesondere wenn entprellen volatile ist kann sich das zwischendurch
durchaus ändern.
Das wird von rechts nach links ausgeführt und wenn die beteiligten Typen
Klassen sind, dann kann man das in der Dokumentation oder im Quelltext
der Klasse nachlesen, die den Zuweisungsoperator und evtl. noch
Type-Cast-Operatoren implementiert.
Und all das bräuchte nicht weiter diskutiert werden, wenn man solche
Konstrukte einfach nicht nutzt.
Oliver
P.S:
Häufig sieht man das auch in C++ eigentlich überhaupt nicht. Da gibt es
eigentlich hier nur den einen, der das Beispiel von oben auch verbrochen
hat.
Das Beispiel zeigt genau den Grund, warum man das nicht machen soll. Das
sieht der Verursacher zwar anders (der findet seine Idee toll), aber
egal. Murks bleibt Murks.
Das o.a. Beispiel stammt von hier:
Beitrag "Re: C/C++ Objektmethoden"
und basiert auf unerwartetem Operator-Overloading. Die Grundregel des
"principle of least surprise", die das verletzt, gilt genauso für Rust
und andere Programmiersprachen.
Oliver
Oliver S. schrieb:> Das o.a. Beispiel stammt von hier:>> Beitrag "Re: C/C++ Objektmethoden">> und basiert auf unerwartetem Operator-Overloading. Die Grundregel des> "principle of least surprise", die das verletzt, gilt genauso für Rust> und andere Programmiersprachen.
Danke für den Link, das erklärt vieles.
Peter D. schrieb:> In C++ sieht man ja oft solche Mehrfachzuweisungen:>
1
>counter=flankenerkennung=entprellen=taster;
2
>
> Unter C ist die Bedeutung eindeutig, alle Variablen werden auf den> gleichen Wert gesetzt.> Unter C++ ist die Bedeutung aber eine völlig andere. Wo kann man> nachlesen, was das bedeutet?
Der Kopierzuweisungsoperator ist ein C++ ein Operator, den man selbst
definieren und überladen kann. Was der Operator dann tut, ist der
Sprache egal. Allerdings (wie oben schon geschrieben), sollte man dabei
die übliche Erwartungshaltung erfüllen, und zwar der Operator (etwa bei:
lhs = rhs) hat als Resultat das lhs-Objekt und übt einen bestimmten
Seiteneffekt auf lhs aus, nämlich kopiert die non-const Attribute.
DPA schrieb:> Peter D. schrieb:>> In C++ sieht man ja oft solche Mehrfachzuweisungen:counter =>> flankenerkennung = entprellen = taster;>> Unter C ist die Bedeutung eindeutig, alle Variablen werden auf den>> gleichen Wert gesetzt.>> Nein, dass ist nicht der fall.>> flankenerkennung = entprellen = taster;>> entspricht:>> entprellen = taster;> flankenerkennung = entprellen;>> Insbesondere wenn entprellen volatile ist kann sich das zwischendurch> durchaus ändern.
Auch implizite Typkonvertierungen können zu Unterschieden führen:
1
#include<stdio.h>
2
#include<stdint.h>
3
4
intmain(void){
5
doubled;
6
int16_ti16;
7
uint8_tui8;
8
9
ui8=i16=d=-1234.5;
10
11
printf("d=%f, i16=%d, u8=%u\n",d,i16,ui8);
12
}
ergibt
1
d=-1234.500000, i16=-1234, u8=46
Olaf B. schrieb:> wird bei Ruby öfters verwandt. In C++ nicht.
In Ruby und Python ist die Zuweisung an gewöhnliche Variablen (also
keine Membervariablen) nicht überladbar, und es gibt keine impliziten
Typkonvertierungen, weswegen es dort diesbezüglich keine Überraschungen
gibt.
Ich verwende die Mehrfachzuweisung auch in C und C++, aber nur für
primitive Datentypen (int, double usw.) und nur für Variablen gleichen
Typs. Damit sind Überraschungen ebenfalls ausgeschlossen.
Oliver S. schrieb:> Das o.a. Beispiel stammt von hier:>> Beitrag "Re: C/C++ Objektmethoden"
Das ist wirklich gruselig, noch gruseliger als die Vergewaltigung der
Bitshift- als I/O-Operatoren in iostream. Hätte der Fanboy statt des =
wenigstens das ohnehin schon versaute << genommen, wäre die Überraschung
nicht ganz so heftig.
Yalu X. schrieb:> Das ist wirklich gruselig, noch gruseliger als die Vergewaltigung der> Bitshift- als I/O-Operatoren in iostream. Hätte der Fanboy statt des => wenigstens das ohnehin schon versaute << genommen, wäre die Überraschung> nicht ganz so heftig.
Nur, dass << von links nach rechts ausgewertet wird.
Heiko L. schrieb:> Nur, dass << von links nach rechts ausgewertet wird.
Stimmt. Dann also andersherum:
1
taster>>entprellen>>flankenerkennung>>counter;
Das passt ohnehin besser zu der hierzulande üblichen Leserichtung.
Oder auch
1
taster|entprellen|flankenerkennung|counter;
Das erinnert an eine Shell-Pipline, die eine ähnliche Funktion hat.
Ein Rest des bösen Überraschungseffekts bleibt aber dennoch.
Warum müssen dafür unbedingt die Operatoren missbraucht werden, wenn es
auch mit benamsten Memberfunktionen geht?
Also so:
Ja, richtig. Bei dem Beispiel mit den Zuweisungen würde ich davon
ausgehen, dass das Objekt ganz Rechts, also "taster", const sein könnte.
Beim >> würde ich darauf nicht wetten.
Insgesamt wäre ich bei Operatoren vorsichtig, ihnen eine Bedeutung zu
geben, die nicht "vom Standard diktiert" wurde. Wenn die Bedeutung kein
common-sense ist, führt der Verzicht auf die Benamung schlicht dazu,
dass man nur noch mit irgendeinem wildcard-symbol konfrontiert ist.
Schlimmer noch, als das bei benannten Funktionen z.T. schon der Fall
ist.
Die >>-Kette gibt z.B. klassischer Weise das Objekt links zurück, nicht
das rechte.
Heiko L. schrieb:> Insgesamt wäre ich bei Operatoren vorsichtig, ihnen eine Bedeutung zu> geben, die nicht "vom Standard diktiert" wurde.
Die C++ Core Guidelines haben wohl nicht ohne Grund eine eigene Regel
dafür kreiert, und bringen das auf den Punkt:
C.61: A copy operation should copy
Oliver
Heiko L. schrieb:> Insgesamt wäre ich bei Operatoren vorsichtig, ihnen eine Bedeutung zu> geben, die nicht "vom Standard diktiert" wurde. Wenn die Bedeutung kein> common-sense ist, führt der Verzicht auf die Benamung schlicht dazu,> dass man nur noch mit irgendeinem wildcard-symbol konfrontiert ist.
Dann schau dir mal boost.spirit an. Da treiben sie die Operator Abuse
auf die Spitze. Siehe https://de.wikipedia.org/wiki/Spirit_(Parser)
Rolf M. schrieb:> Heiko L. schrieb:>> Insgesamt wäre ich bei Operatoren vorsichtig, ihnen eine Bedeutung zu>> geben, die nicht "vom Standard diktiert" wurde. Wenn die Bedeutung kein>> common-sense ist, führt der Verzicht auf die Benamung schlicht dazu,>> dass man nur noch mit irgendeinem wildcard-symbol konfrontiert ist.>> Dann schau dir mal boost.spirit an. Da treiben sie die Operator Abuse> auf die Spitze. Siehe https://de.wikipedia.org/wiki/Spirit_(Parser)
Wobei das ein in sich abgeschlossenes Modul ist und die Operatoren
keinerlei Verwendung außerhalb der Definition der Grammatik anstreben.
Heiko L. schrieb:> Rolf M. schrieb:>> Heiko L. schrieb:>>> Insgesamt wäre ich bei Operatoren vorsichtig, ihnen eine Bedeutung zu>>> geben, die nicht "vom Standard diktiert" wurde. Wenn die Bedeutung kein>>> common-sense ist, führt der Verzicht auf die Benamung schlicht dazu,>>> dass man nur noch mit irgendeinem wildcard-symbol konfrontiert ist.>>>> Dann schau dir mal boost.spirit an. Da treiben sie die Operator Abuse>> auf die Spitze. Siehe https://de.wikipedia.org/wiki/Spirit_(Parser)>> Wobei das ein in sich abgeschlossenes Modul ist und die Operatoren> keinerlei Verwendung außerhalb der Definition der Grammatik anstreben.
Die Grammatik hat aber nichts mit der Semantik zu tun!
Da verwechselt Du was. Es gibt nichts außerhalb der Grammatik bei einer
formalen Sprache.