Czy jest „bardzo zła rzecz”, która może się zdarzyć &&=
i ||=
została użyta jako cukier syntaktyczny do bool foo = foo && bar
i bool foo = foo || bar
?
c++
boolean-operations
Kache
źródło
źródło
x ||= y
grubsza odpowiednikiem C ++x = x ? x : y;
dla żadnego typu? Innymi słowy, „ustaw na y, jeśli jeszcze nie zostało ustawione”. Jest to znacznie bardziej przydatne niż C czy C ++x ||= y
, które (z wyjątkiem przeciążania operatorów) spowodowałyby „ustaw x na,(bool)y
chyba że już ustawione”. Nie chcę do tego dodawać kolejnego operatora, wydaje się to trochę słabe. Po prostu napiszif (!x) x = (bool)y
. Ale tak naprawdę nie używambool
zmiennych na tyle, by chcieć dodatkowych operatorów, które są naprawdę przydatne tylko w tym jednym typie.&&=
lub||=
jest po prostu to, że C ich nie ma. Jestem całkiem pewien, że powodem, dla którego C ich nie ma, jest to, że funkcjonalność nie została uznana za wystarczająco korzystną.bool foo = foo || bar;
wywoływałaby niezdefiniowane zachowanie, ponieważfoo
nie została zainicjowana przed ocenąfoo || bar
. Oczywiście ma to być coś podobnego,bool foo = …initialization…; …; foo = foo || bar;
a pytanie jest wtedy aktualne.Odpowiedzi:
A
bool
może być tylkotrue
lubfalse
w C ++. W związku z tym używanie&=
i|=
jest stosunkowo bezpieczne (chociaż nie podoba mi się ten zapis). To prawda, że będą wykonywać operacje bitowe, a nie operacje logiczne (i dlatego nie będą powodować zwarcia), ale te operacje bitowe są zgodne z dobrze zdefiniowanym odwzorowaniem, które jest skutecznie równoważne operacjom logicznym, o ile oba operandy są typubool
. 1W przeciwieństwie do tego, co powiedzieli inni ludzie, a
bool
w C ++ nigdy nie może mieć innej wartości, takiej jak2
. Podczas przypisywania tej wartości do abool
, zostanie ona przekonwertowanatrue
zgodnie ze standardem.Jedynym sposobem uzyskania nieprawidłowej wartości w a
bool
jest użyciereinterpret_cast
wskaźników:Ale ponieważ ten kod i tak skutkuje niezdefiniowanym zachowaniem, możemy bezpiecznie zignorować ten potencjalny problem w dostosowaniu kodu C ++.
1 Trzeba przyznać, że jest to dość duże zastrzeżenie, co ilustruje komentarz Angew:
Powodem jest to, że
b & 2
przeprowadza promocję liczb całkowitych w taki sposób, że wyrażenie jest następnie równoważnestatic_cast<int>(b) & 2
, co powoduje0
, że jest następnie konwertowany z powrotem nabool
. Więc to prawda, że istnienieoperator &&=
litery poprawiłoby bezpieczeństwo typu.źródło
||
i&&
skrót, tj. drugi argument nie jest operandem, jeśli pierwszy argument totrue
(odpowiedniofalse
dla&&
).|
,&
,|=
I&=
zawsze oceniać oba operandy.&=
dla lewej strony typubool
, bo to zupełnie możliwe, że po prawej stronie, aby być typu innego niżbool
(jakislower
lub innej funkcji stdlib C, która powraca niezerowe dla prawdziwej wartości). Gdybyśmy mieli hipotezę&&=
, prawdopodobnie zmusiłoby to prawą stronę do przejścia nabool
, co&=
nie. Innymi słowy,bool b = true; b &= 2;
powodujeb == false
.&&
i&
mają inną semantykę:&&
nie oceni drugiego operandu, jeśli pierwszy operand jestfalse
. czyli coś w stylujest bezpieczny, ale
nie jest, chociaż oba operandy są typu
bool
.To samo dotyczy
&=
i|=
:zachowa się inaczej niż:
źródło
Krótka odpowiedź
Wszyscy operatorzy
+=
,-=
,*=
,/=
,&=
,|=
... są arytmetyczny i zapewnić taką samą oczekiwania:Jednak operatory
&&=
i||=
byłyby logiczne, a operatory te mogą być podatne na błędy, ponieważ wielu programistów spodziewafoo()
się, że będą zawsze wywoływanix &&= foo()
.Czy naprawdę musimy uczynić C / C ++ jeszcze bardziej złożonym, aby uzyskać skrót
x = x && foo()
?Czy naprawdę chcemy bardziej zaciemnić tajemnicze stwierdzenie
x = x && foo()
?A może chcemy napisać znaczący kod
if (x) x = foo();
?Długa odpowiedź
Przykład dla
&&=
Jeśli
&&=
operator był dostępny, to ten kod:jest równa:
Ten pierwszy kod jest podatny na błędy, ponieważ wielu programistów pomyślałoby, że
f2()
jest zawsze wywoływany niezależnie odf1()
zwracanej wartości. To tak, jakby pisać,bool ok = f1() && f2();
gdzief2()
jest wywoływane tylko wtedy, gdyf1()
zwracatrue
.f2()
aby wywoływano go tylko wtedy , gdyf1()
zwracatrue
, drugi kod powyżej jest mniej podatny na błędy.f2()
aby zawsze dzwoniono),&=
wystarczy:Przykład dla
&=
Co więcej, kompilatorowi łatwiej jest zoptymalizować powyższy kod niż poniższy:
Porównaj
&&
i&
Możemy się zastanawiać, czy operatory
&&
i&
dają taki sam wynik, gdy są stosowane nabool
wartościach?Sprawdźmy, używając następującego kodu C ++:
Wynik:
Wniosek
Dlatego TAK możemy zastąpić
&&
przez&
dobool
wartości ;-)Więc lepiej używać
&=
zamiast&&=
.Możemy uznać
&&=
za bezużyteczne dla wartości logicznych.To samo dotyczy
||=
Jeśli programista chce
f2()
być wywoływany tylko wtedy , gdyf1()
zwracafalse
, zamiast:Radzę następującą, bardziej zrozumiałą alternatywę:
lub jeśli wolisz wszystko w jednym stylu:
źródło
success = success && DoImportantStuff()
if(success) success = DoImportantStuff()
. Gdyby zeznaniesuccess &&= DoImportantStuff()
było dozwolone, wielu programistów pomyślałoby, żeDoImportantStuff()
zawsze jest wywoływane niezależnie od wartościsuccess
. Mam nadzieję, że ta odpowiedź jest odpowiedzią na Twoje wątpliwości ... Poprawiłem także wiele części mojej odpowiedzi. Proszę, powiedz mi, czy moja odpowiedź jest teraz bardziej zrozumiała? (o celu komentarza) Do zobaczenia ;-)success &&= DoImportantStuff()
było dozwolone, wielu programistów pomyślałoby, żeDoImportantStuff()
zawsze nazywa się je bez względu na wartość sukcesu”. Można to jednak powiedziećif (success && DoImportantStuff())
. O ile pamiętają logikę składni if, z którą nie powinni mieć problemu&&=
.f1()
zawsze ocenia się w,ok &&= f(1)
ale nie zakładam, że zawsze ocenia się wok = ok && f(1)
. Wydaje mi się to równie prawdopodobne.v1 += e2
się, że będę odpowiednikiem cukru syntaktycznegov1 = v1 + e1
dla zmiennej v1 i wyrażenia e2. Tylko skrótowa notacja, to wszystko.