Która zamiana waszym zdaniem lepsiejsza?

0
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 :)...

8

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).

6

Druga metoda. Im mniej czytelny kod, tym bardziej bezpieczna posada.

A serio, to std::swap.

1

Jak bardzo nie lubisz std:), to całkiem spoko jest XOR swap

0

Przecież

a = a + b - ( b = a )

nawet nie działa i obie wartości będą mieć wartość b.

3

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.

5

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.


Edit Sprawdziłem co robi z tym kompilator: * dla [clang w kodzie wynikowym w zasadzie nie ma różnicy](https://godbolt.org/z/pqfNj0) (zmienia się jedynie kolejność instrukcji), ale za to clang zgłasza warrning `warning: unsequenced modification and access to 'b' [-Wunsequenced]` dla przekombinowanej wersji. * dla [msvc niezdefiniowane zachowanie się odgryza](https://godbolt.org/z/xW01wX) kompilator robi tylko jedno przypisanie - czyli kończy się bugiem.
0

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ść?

0

Ja preferuję xorowanie.

a =^ b
b =^ a
a =^ b
0

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
4

Dla fanatyków C++17:

std::tie(a,b) = std::pair(b,a);

https://wandbox.org/permlink/t6WXvYTSy1kdwCx1

1 użytkowników online, w tym zalogowanych: 0, gości: 1