temp = b;
b = a;
a = temp;
czy
a = a + b - ( b = a );
czy może jeszcze jakaś inna magia aby zamienić a wartością z b?
ale głównie pytanie którą opcje wolicie i dlaczego :)...
temp = b;
b = a;
a = temp;
czy
a = a + b - ( b = a );
czy może jeszcze jakaś inna magia aby zamienić a wartością z b?
ale głównie pytanie którą opcje wolicie i dlaczego :)...
https://en.cppreference.com/w/cpp/algorithm/swap, ponieważ jest czytelna i mieści się w jednej linijce.
czy może jeszcze jakaś inna magia
Kod powinien być czytelny, nie magiczny - zwłaszcza że Twój drugi przykład jest podatny na integer overflow
, więc dla całkiem sporej liczby danych zwróci nieoczekiwane rezultaty (w momencie w którym a + b
zwróci liczbę niemieszczącą się w typie).
Druga metoda. Im mniej czytelny kod, tym bardziej bezpieczna posada.
A serio, to std::swap
.
Jak bardzo nie lubisz std
:), to całkiem spoko jest XOR swap
Przecież
a = a + b - ( b = a )
nawet nie działa i obie wartości będą mieć wartość b.
Druga wersja zawiera UB, jeśli mnie oczy nie mylą, nie masz określone czy najpierw wykona się b = a
, czy też będzie pobrana wartość b
do wyrażenia a + b
.
W C++ kompilator obowiązuje zasada "As If" ("Tak jak"), dzięki, której kompilator może robić różne cuda.
Ma to swoje konsekwencje.
Takie micro-optymalizacje nie mają sensu bo, po włączeniu -o2
i tak kompilator zrobi to po swojemu.
Nie zdziwiłbym się, jakby dla kompilatora nie było różnicy, albo wręcz ta udziwniona wersja była gorzej zinterpretowana przez kompilator.
Takie udziwnienia są trudne w czytaniu, zrozumieniu, mogą być trudniejsze do zinterpretowania przez kompilator, przez co koniec końców będą wolniejsze.
Na dodatek, coś mi się wydaje, że a = a + b - ( b = a );
to jest niezdefiniowane zachowanie, ponieważ kolejność ewaluacji argumentów operatorów dodawania i odejmowania jest niezdefiniowana.
Czyli dla operacji odejmowania nie wiadomo, co będzie najpierw policzone: a + b
czy może b = a
.
Wszelkie optymalizacje powinny być poddane pomiarom (co zwykle nie jest łatwe w obiektywnym wykonaniu), przed podjęciem decyzji czy ich używać czy nie.
We współczesnych procesorach i kompilatorach, jest zastosowanych tyle sztuczek, że często coś co wygląda na optymalizację, przynosi skutek odwrotny.
Przewidzenie wszystkich skutków ubocznych be pomiarów, wymaga bardzo specjalistycznej wiedzy.
Ten kod:
a = a + b - ( b = a )
do tej pory pojawił się na forum z tego co pamiętam kilka razy i za każdym razem w komentarzach pod postem go zawierającym pisano, że to UB, że jest nieczytelny i na pierwszy rzut oka nie wiadomo w ogóle co robi (a powinien). Zgadzam się jak najbardziej z takimi uwagami i nie chciałbym mieć do czynienia z kimś, kto w taki sposób rozwiązuje problemy.
Skąd go bierzecie? Ktoś go na produkcji ma? A może w jakimś tutorialu wystąpił i stąd jego popularność?
Ja preferuję xorowanie.
a =^ b
b =^ a
a =^ b
Tak serio, to rejestry są wolne i takie coś powinno działać, ale kompilator tego może nie ogarnąć.
a = b
b = a
Pod bebechami powinno być.
mov rax, a
mov rcx, b
mov a, rcx
mov b, rax