Operator potrójny?: A jeśli… else

80

Czy w C ++ operator?: Jest szybszy niż instrukcje if () ... else? Czy są między nimi różnice w skompilowanym kodzie?

Xirdus
źródło
Trudne pytanie, ponieważ zależałoby również od ustawienia optymalizacyjnego kompilatora.
extraneon
3
To z pewnością zależy od tego, co robisz wewnątrz gałęzi. Operator warunkowy dopuszcza tylko wyrażenia, a ifzezwala na instrukcje.
Gumbo
4
powiązane: trójskładnikowy czy nie trójskładnikowy?
Nick Dandoulakis,
8
Jakiś facet przypadkowo zdecydował się edytować moje trzyletnie pytanie w porządku, przepisując pytanie tak, by brzmiało zupełnie inaczej niż ja i dodając trochę niepotrzebnego kodu, który sprawia, że ​​cały problem jest bezcelowy, ponieważ dzięki ciągłemu składaniu, obie te próbki sprowadzają się do prostego "wyniku = 5 ". Cofam.
Xirdus,
Wersja zestawu cmov vs jmp stackoverflow.com/questions/14131096/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Odpowiedzi:

88

Zależy od twojego kompilatora, ale w każdym nowoczesnym kompilatorze nie ma zasadniczo żadnej różnicy. To coś, o co nie powinieneś się martwić. Skoncentruj się na łatwości utrzymania swojego kodu.

ptomato
źródło
1
+1 W przypadku wielu aplikacji różnica perf nie jest warta rozważenia, nawet w przypadku naprawdę dump kompilatora.
4
Jeśli chodzi o łatwość utrzymania kodu, wolałbym, gdyby ... inaczej. Przynajmniej dla mnie jest to łatwiejsze do odczytania.
Exa
2
@Exa: Zależy od kontekstu. Operator trójargumentowy jest często lepszy podczas inicjowania obiektu.
Nemanja Trifunovic,
@Nemanja: Dlatego powiedziałem „Przynajmniej dla mnie”. Miałem na myśli tylko czytelność kodu :)
Exa
1
@kotlinski, nie mówię, że warunek jest mniej konserwowalny niż jeśli. Oba są jaśniejsze w pewnych, różniących się okolicznościach, jak opisano w odpowiedziach na pytanie trójskładnikowe lub nie, połączone powyżej.
ptomato
106

To nie jest szybsze. Istnieje jedna różnica, kiedy można zainicjować stałą zmienną w zależności od jakiegoś wyrażenia:

const int x = (a<b) ? b : a;

Nie możesz zrobić tego samego z if-else.

Kirill V. Lyadvinsky
źródło
20
@Developer Art: Co nie jest możliwe w przypadku constzmiennej.
Job
1
Możesz utworzyć zmienną inną niż stała, przypisać do niej w if / else, a następnie utworzyć nową zmienną stałą i skonstruować ją za pomocą zmiennej innej niż const. Raczej marnotrawne, ale dalekie od niemożliwego.
Puppy
7
A co ze starym dobrym max? const int x = max(a,b);działa dobrze.
bobobobo
3
@bobobobo ha! Kiedy przeczytałem twój komentarz, pomyślałem, że poleceniem, które sugerowałeś, było max ? const int x = max(a,b);i pomyślałem, że! Co to do cholery jest! potem przeczytałem go ponownie i zauważyłem, że znak zapytania nie był stały! biorąc pod uwagę temat, myślę, że uzasadnione było myślenie? był częścią dowództwa! :)
dewd
2
Możesz użyć const int x = [&] -> int { if (a < b) return b; else return a; }.
LF
43

Widziałem, jak GCC zamieniało operator cmovwarunkowy w instrukcje (ruch warunkowy), jednocześnie zamieniając ifinstrukcje w gałęzie, co w naszym przypadku oznaczało, że kod był szybszy, gdy używał operatora warunkowego. Ale to było kilka lat temu i najprawdopodobniej dzisiaj, oba skompilowałyby się do tego samego kodu.

Nie ma gwarancji, że skompilują się do tego samego kodu. Jeśli potrzebujesz wydajności, jak zawsze, zmierz . A kiedy już zmierzysz i odkryjesz, że 1. twój kod jest zbyt wolny, i 2. to ten konkretny fragment kodu jest winowajcą, wtedy przestudiuj kod asemblera wygenerowany przez kompilator i sprawdź sam, co się dzieje.

Nie ufaj złotym regułom, takim jak „kompilator zawsze wygeneruje wydajniejszy kod, jeśli użyję operatora warunkowego”.

jalf
źródło
2
+1. Kiedy tworzyłem na PS3 przy użyciu GCC, używanie warunkowych zamiast „jeśli” było przydatne, aby uniknąć rozgałęzień.
Johan Kotlinski
Czy jest to specyficzne dla języka c? Standard C ++ mówi, Only one of the second and third expressions is evaluated. Every value computation and side effect associated with the first expression is sequenced before every value computation and side effect associated with the second or third expression.co najwyraźniej uniemożliwia kompilatorowi generowanie cmoveinstrukcji.
Joey.Z
2
@zoujyjs nie, C ma tę samą zasadę. Ale zgodnie z zasadą as-if kompilator może oszukiwać, o ile wynik końcowy jest poprawny. Dopóki nie ma żadnych skutków ubocznych, kompilator może dokonać optymalizacji.
jalf
Jak zaimplementować if else z cmov? Mov do wartości 1 + cmov do wartości 2?
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
1
UWAGA: Ta rada jest nieaktualna (cira 2010), nie mogłem jej odtworzyć na gcc 4.4 lub nowszym.
ACyclic
15

Są takie same, jednak operator trójskładnikowy może być używany w miejscach, w których trudno jest użyć if / else:

printf("Total: %d item%s", cnt, cnt != 1 ? "s" : "");

Wykonanie tej instrukcji z if / else wygenerowałoby zupełnie inny skompilowany kod.


Aktualizacja po 8 latach ...

Właściwie myślę, że tak byłoby lepiej:

printf(cnt == 1 ? "Total: %d item" : "Total: %d items", cnt);

(właściwie jestem pewien, że „% d” w pierwszym ciągu znaków można zamienić na „jeden”)

James Curran
źródło
8
Nie potrzebuje nawet operatora trójskładnikowego:printf("Total: %d item%s", cnt, "s" + (cnt==1));
MSalters
@MSalters, ale daje to podwójne null na końcu ciągu, co może być problemem w innych sytuacjach, w których podwójne null coś znaczy (np. W lpStrFilterskładniku struktur OPENFILENAME )
bobobobo
1
@bobobobo: Nie. %sDrukuje do, ale bez \0ciągu źródłowego.
MSalters
@MSalters jak to printf("Total: %d item%s", cnt, "s" + (cnt==1));działa?
Quirk
2
@Quirk: (cnt==1)jest prawdą lub fałszem, co jest konwertowane na 0 lub 1. „s” jest wskaźnikiem do łańcucha zakończonego znakiem nul. Dodanie jednego pomija jeden znak (znaki). Więc to wypisuje „s” lub „”.
MSalters
3

Niezależnie od skompilowanego kodu, są semantycznie różne. <cond>?<true expr>:<false expr>jest wyrażeniem i if..else..jest stwierdzeniem.

Chociaż składnia wyrażeń warunkowych wydaje się niezręczna, to dobrze. Jesteś zmuszony podać a, <false expr>a dwa wyrażenia są sprawdzane pod względem typu.

Odpowiednik if..else..w języku funkcjonalnym opartym na wyrażeniach, takim jak Lisp, Haskell jest ? :w C ++, zamiast if..else..instrukcji.

amdyes
źródło
2

Nie jesteś zmuszony umieścić tego wszystkiego w jednej linii: -

x = y==1 ?
    2
    :// else
    3;

Jest to o wiele jaśniejsze niż if / else, ponieważ od razu widać, że obie gałęzie prowadzą do przypisania x.

QuentinUK
źródło
Możesz także zainicjować const
QuentinUK
0

Spodziewałbym się, że na większości kompilatorów i platform docelowych będą przypadki, w których „if” jest szybsze i przypadki, w których?: Jest szybsze. Będą również przypadki, w których jedna forma jest mniej lub bardziej zwarta niż druga. Które przypadki faworyzują jedną lub drugą formę, będą się różnić w zależności od kompilatorów i platform. Jeśli piszesz kod krytyczny dla wydajności w osadzonym mikro, spójrz, co kompilator generuje w każdym przypadku i zobacz, co jest lepsze. Na komputerze typu „mainstream”, ze względu na problemy z buforowaniem, jedynym sposobem sprawdzenia, która jest lepsza, jest porównanie obu formularzy w sposób przypominający rzeczywistą aplikację.

supercat
źródło
0

W CA dostępny jest operator trójskładnikowy „?:” Do konstruowania wyrażeń warunkowych formularza

exp1 ? exp2:exp3

gdzie exp1, exp2 i exp3 są wyrażeniami

na przykład

        a=20;
        b=25;
        x=(a>b)?a:b;

        in the above example x value will be assigned to b;

Można to zapisać za pomocą instrukcji if..else w następujący sposób

            if (a>b)
             x=a;
             else
             x=b;

** Dlatego nie ma różnicy między tymi dwoma. To dla programisty, aby mógł łatwo pisać, ale dla kompilatora oba są takie same. *

ksrao
źródło
0

Podczas cofania jakiegoś kodu (którego nie pamiętam, kilka lat temu) zauważyłem pojedynczą różnicę między kodem maszynowym:? a jeśli jeszcze. Don't remember much but it is clear that implementation of both is different.

Ale radzę Ci nie wybierać jednego z nich ze względu na jego wydajność, wybierz ze względu na czytelność kodu lub wygodę. Miłego kodowania

Pervez Alam
źródło
Różnica była jednym z nich był przy goto do rozgałęzienia i innych używał saome natywnej instrukcji, nie pamiętam który z nich był przy którym ..
Pervez Alam
0

Operator trójargumentowy zawsze zwraca wartość. Więc w sytuacji, gdy chcesz uzyskać jakąś wartość wyjściową z wyniku i są tylko 2 warunki, zawsze lepiej użyć operatora trójskładnikowego. Użyj if-else, jeśli którykolwiek z powyższych warunków nie jest spełniony.

Raheel Afzal
źródło
6
Co to właściwie jest? Czy wiesz, o czym mówisz?
kwantowy
0

Myślę, że są sytuacje, w których wbudowane if może dać „szybszy” kod ze względu na zakres, w jakim działa. Tworzenie i niszczenie obiektów może być kosztowne, więc rozważ następujący scenariusz:

class A{
    public:
    A() : value(0) {
        cout << "Default ctor" << endl;
    }
    A(int myInt) : value(myInt)
    {
        cout << "Overloaded ctor" << endl;
    }

    A& operator=(const A& other){
        cout << "= operator" << endl;
        value = other.value; 
    }

    ~A(){
        cout << "destroyed" << std::endl;
    }

    int value;

};


int main()
{
   {
       A a;
       if(true){
           a = A(5);
       }else{
           a = A(10);
       }
   }

   cout << "Next test" << endl;
   {
        A b = true? A(5) : A(10);
   }
   return 0;
}

Z tym kodem wynik będzie:

Default ctor                                                                                                                                                                                                                      
Overloaded ctor                                                                                                                                                                                                                   
= operator                                                                                                                                                                                                                        
destroyed                                                                                                                                                                                                                         
destroyed                                                                                                                                                                                                                         
Next test                                                                                                                                                                                                                         
Overloaded ctor                                                                                                                                                                                                                   
destroyed  

Dlatego wstawiając if, oszczędzamy szereg operacji potrzebnych do utrzymania atego samego zakresu co b. Chociaż jest wysoce prawdopodobne, że szybkość oceny stanu jest dość równa w obu scenariuszach, zmiana zakresu zmusza Cię do wzięcia pod uwagę innych czynników, których inline pozwala uniknąć.

Eric
źródło
A co zA a(true ? 5 : 10);
Quest
-1

Teraz nie mogę ci w tym pomóc, być może będę mógł pomóc w drugorzędnym pytaniu poniżej, czy chcę go użyć? Jeśli chcesz tylko poznać prędkość, zignoruj ​​mój komentarz.

Mogę tylko powiedzieć, że proszę być bardzo sprytnym, kiedy używać trójskładnika? : operator. Może to być zarówno błogosławieństwo, jak i przekleństwo dla czytelności.

Zadaj sobie pytanie, czy łatwiej ci to przeczytać przed użyciem

int x = x == 1 ? x = 1 : x = 1;

if (x == 1)
{
   x = 1
}
else
{
   x = 2
}

if (x == 1)
    x = 1
else
    x = 1

Tak, wykonanie kodu w 100% fałszywego wygląda głupio. Ale ta mała sztuczka pomogła mi przeanalizować moją czytelność kodu. To czytelność operatora, na który patrzysz w tym przykładzie, a nie treść.

WYGLĄDA czysto, podobnie jak przeciętna deska sedesowa i klamka

Z mojego doświadczenia, które jest ograniczone, widziałem bardzo niewielu ludzi, którzy faktycznie byli w stanie szybko ekstradować informacje wymagane od operatora trójskładnikowego, unikając ich, chyba że w 100% są pewni, że jest lepiej. Myślę, że to ból do naprawienia, gdy jest podłączony do sieci

Proclyon
źródło
5
pierwsza linia powinna prawdopodobnie czytać int x = x == 1 ? 1 : 2lub być możeint x = (x == 1) ? 1 : 2
Hasturkun
Chodziło mi tylko o pokazanie widoku kodu, czystość jednej linii jest fajna, tak. Ale jeśli chcesz zobaczyć CONDITION / ASSIGNEMENT, zawartość kodu może być fałszywa. Jeśli chcesz zobaczyć, co jest tym, patrzysz na samego operatora i lokalizację. Widzę słowo JEŻELI i () Wiem, ach, to jest warunek. Widzę A = B? CONDITION: CONDITION Czy od razu to zauważyłeś? Większość ludzi, których znam ten program, nie wie, może to dlatego, że większość ludzi, których znam, to nowicjusze, tak jak ja. Masz rację, chociaż liczby są bezsensowne, o to chodzi.
Proclyon,
2
Pierwsza linia zdecydowanie potrzebuje nawiasów. Być może „int x = (y == 1)? 0: 1;” lub „int x = ((y == 1)? 0: 1);”
supercat
6
Przepraszam, ale nie mam problemu z zobaczeniem zadania. Jeśli zdecydujesz się zbytnio skomplikować przykład, aby przedstawić swój punkt widzenia, to jest twój problem. Dlaczego nie napiszesz x = x = 1;wszędzie, a potem narzekasz, że zadanie jest zbyt skomplikowane i powinno się go unikać.
UncleBens
-4

Nie, są konwertowane na dokładnie ten sam kod wykonywalny.

Alex F.
źródło
7
-1: na jakiej wersji jakiego kompilatora, na jakiej platformie, z jakim kodem?
Puppy
3
Oczywiście DeadMG: kompilator VB6!
Alex F,