Il fascino di operatore ternario vs istruzione if

Sto sfogliando un po ‘ di codice e ho trovato un paio di ternario operatori in esso. Questo codice è una libreria che usiamo, e dovrebbe essere abbastanza veloce.

Sto pensando se stiamo salvando nulla tranne che per lo spazio c’.

Qual è la tua esperienza?

  • Se ternario erano più veloci di se-dichiarazioni (o viceversa), i compilatori sarebbe sicuramente convertire l’uno e l’altro. Così non dovrebbero avere prestazioni diverse caratteristiche (supponendo che si fanno entrambe le istruzioni con pari qualità).
  • Se non altro, è un µ-ottimizzazione. In caso di dubbio: benchmark.
  • possibile duplicato di Vantaggi di usare il condizionale ?: (ternario) operatore
  • eh… sbattere la vecchia questione al fine di promuovere il proprio? si potrebbe trovare te stesso bannato il mio amico…
  • nawfal: quel link è specifico per C#, quindi IMHO non è una buona duplicati
  • voi ragazzi … 🙂
  • Sarebbe meglio chiedere una sola lingua, è probabile che non sia possibile rispondere altrimenti. C++ versione: stackoverflow.com/questions/3565368/ternary-operator-vs-if-else

 

5 Replies
  1. 49

    Prestazioni

    L’operatore ternario non differiscono in termini di prestazioni da un equivalente scritto if/else istruzione… si può risolvere bene per la stessa rappresentazione nell’Albero di Sintassi Astratta, subiscono le stesse ottimizzazioni ecc..

    Cose che si possono fare solo con ? :

    Se stai inizializzando un costante o di riferimento, o il valore da utilizzare all’interno di un membro di inizializzazione elenco, quindi if/else dichiarazioni non possono essere utilizzati, ma ? : può essere:

    const int x = f() ? 10 : 2;
    
    X::X() : n_(n > 0 ? 2 * n : 0) { }

    Factoring per conciso codice

    Chiavi motivi per utilizzare ? : includono la localizzazione, e di evitare in modo ridondante ripetizione di altre parti dello stesso consolidato/funzione chiamate, ad esempio:

    if (condition)
        return x;
    else
        return y;

    …è solo preferibile…

    return condition ? x : y;

    …sulla leggibilità motivi se si tratta di molto inesperto, programmatori, o alcuni termini sono abbastanza complicato che il ? : struttura si perde nel rumore. Nei casi più complessi come:

    fn(condition1 ? t1 : f1, condition2 ? t2 : f2, condition3 ? t3 : f3);

    Un equivalente if/else:

    if (condition1)
        if (condition2)
            if (condition3)
                fn(t1, t2, t3);
            else
                fn(t1, t2, f3);
        else if (condition3)
                fn(t1, f2, t3);
            else
                fn(t1, f2, f3);
    else
        if (condition2)
           ...etc...

    Che un sacco di chiamate di funzione che il compilatore può o non può ottimizzare distanza.

    Non può denominato provvisori migliorare if/else mostruosità di cui sopra?

    Se le espressioni t1, f1, t2 etc. sono troppo dettagliato per tipo ripetutamente, la creazione di nome provvisori possono aiutare, ma poi:

    • Per ottenere prestazioni corrispondenti ? : potrebbe essere necessario utilizzare std::move, tranne quando il temporaneo, è passato a due && parametri in funzione chiamata: quindi si deve evitare. Che, più complesso e soggetto a errori.

    • c ? x : y valuta c, quindi, ma non entrambi x e y, che lo rende sicuro per dire che il test di un puntatore non è nullptr prima di utilizzarlo, fornendo alcuni fallback valore/comportamento. Il codice ottiene solo gli effetti collaterali di qualsiasi x e y è effettivamente selezionato. Con il nome provvisori, potrebbe essere necessario if /else in tutto o ? : all’interno del loro inizializzazione a indesiderate il codice in esecuzione, o di esecuzione di codice più spesso di quanto desiderato.

    Differenza funzionale: unificante tipo di risultato

    Considerare:

    void is(int) { std::cout << "int\n"; }
    void is(double) { std::cout << "double\n"; }
    
    void f(bool expr)
    {
        is(expr ? 1 : 2.0);
    
        if (expr)
            is(1);
        else
            is(2.0);
    }

    L’operatore condizionale versione precedente, 1 subisce una Conversione Standard per double in modo che il tipo di corrispondenza 2.0, il che significa il is(double) sovraccarico viene chiamato anche per il true/1 situazione. Il if/else dichiarazione di non attivare questa conversione: il true/1 ramo chiamate is(int).

    Non è possibile utilizzare le espressioni per un totale complessivo tipo di void di un operatore condizionale sia, mentre sono validi in dichiarazioni sotto un if/else.

    Enfasi: valore di selezione prima e dopo l’azione che necessitano di valori

    C’è una diversa enfasi:

    Un if/else dichiarazione sottolinea la ramificazione prima e ciò che deve essere fatto è secondario, mentre un operatore ternario sottolinea quello che deve essere fatto sulla selezione dei valori di farlo con.

    In diverse situazioni, sia riflettano meglio il programmatore di “naturale” prospettive per il codice e renderlo più facile da capire, verificare e mantenere. Si possono trovare te la selezione di uno o l’altro in base all’ordine in cui si considerano questi fattori quando si scrive il codice se avete lanciato nel “fare qualcosa” per poi trovare che si potrebbe utilizzare uno di una coppia (o pochi) valori a che fare con, ? : è meno dirompente modo per esprimere che e continuare la codifica di “flusso”.

    • l’equivalente diretto della funzione di chiamata senza ternario gli operatori devono utilizzare le variabili intermedie e separare i condizionali. Fintanto che il loro campo di applicazione è locale alla funzione, il compilatore dovrebbe essere in grado di ottimizzare la loro distanza. Senza di loro si sarebbe da scrivere una pagina piena di codice che sarebbe impossibile da leggere e debug, anche se i moderni compilatori sarebbe probabilmente fare un buon lavoro di ottimizzazione esso.
    • bella elaborazione su mia laconico “Creazione provvisori è una seccatura, ma garantisce prestazioni simili a operatore ternario.”. Compilatori, probabilmente sbarazzarsi di almeno alcuni di if/else funzione di albero, ma le cose possono complicarsi con registrazione accantonamenti, i limiti di profondità ecc…. e ‘ difficile sapere se si potrebbe fare tutta la strada.
    • Chiedo perdono qui. Anche se siete di destra che lo spiega. Operatore condizionale può essere utilizzato in un’espressione come se()…else() potrebbe non essere utilizzato. Ho usato questo trucco per risolvere voce 10 in Scott Meyer Più Efficace C++ in un modo diverso in cui ho evitato l’utilizzo di auto_ptr<> . Diamo un’occhiata : siddhusingh.blogspot.com
    • nel 2007 ottobre la sezione alla fine :-P] il codice di ala: try { true ? p = 0, new AudioClip() : 0; } catch (...) { if (p) delete p; }? Che solo totalmente rotto. Non hai notato che p sempre stato impostato a 0, e il new-ed oggetto trapelato?
    • Penso che si fuorviato dal codice. Prova a riformattare il codice nel vostro editor. Non c’è alcuna perdita di memoria. Quello che tutti, sto facendo : sto inizializzando la variabile membro puntatore sulla base di un altro valore della variabile e se non sono di assegnare NULL, Se fosse vero, allora anche io sono prima di assegnare NULL e poi usando la virgola operatore sto chiamando un operatore new. Quando l’ultimo valore viene assegnato il valore se si utilizza l’operatore virgola. In caso di eccezione sono la cattura utilizzando catch(…) , la pulizia di qualsiasi sorte di memoria e quindi generazione ripetuta di nuovo dal costruttore stesso.
    • Si prega di guardare il codice qui sotto. Penso che tu sia confuso con l’approccio che ho preso. Quello che hai detto è giusto, ma non nel contesto che ho scritto. Il codice riportato di seguito deve stampare 10. #include <iostream> #include <string> using namespace std; int main(int argc, char ** argv, char * arge[]) try { cout << “Ciao Mondo!” << endl; string str = “a”; int * p; int * a = (str != “”) ? p=0, new int(10) : 0; if (a == 0) { cout << “a = 0” << endl; } else { cout << “un =” << *un << endl; } return 0; } catch(…) { cerr << “Uncaught exception…” << endl; }
    • scusate, ora ho notato il vostro initialiser elenco è l’incorporazione di queste affermazioni in modo che qualsiasi puntatore è passato al membro di dati. Ma, se new Image() getta quindi theAudioClip sarà deleted pur essendo non inizializzato. Si potrebbe risolvere questo problema: le materie prime puntatori deve essere inizializzato prima che il primo membro di dati (cioè theName) costruttore potrebbe buttare, dato che si dispone di un try/catch intorno al costruttore, come in : theName((theImage = theAudioClip = nullptr, name)). Più bello con puntatore membri di dati di prima, ma ancora fragile.

  2. 8

    Bene…

    Ho fatto un paio di prove con GCC e questa chiamata di funzione:

    add(argc, (argc > 1)?(argv[1][0] > 5)?50:10:1, (argc > 2)?(argv[2][0] > 5)?50:10:1, (argc > 3)?(argv[3][0] > 5)?50:10:1);

    Risultante di codice assembler con gcc -O3 aveva 35 istruzioni.

    Il codice equivalente con if/else + variabili intermedie aveva 36. If/else, utilizzando il fatto che 3 > 2 > 1, ho 44. Non l’ho nemmeno tenta di espandere questo in separata chiamate di funzione.

    Ora non ho fatto alcuna analisi delle prestazioni, né ho fatto un controllo di qualità dei risultante di codice assembler, ma a qualcosa di semplice come questo senza loop e.t.c. Credo che più corto è, meglio è.

    Sembra che c’è qualche valore per ternario operatori, dopo tutto 🙂

    Che è solo se il codice di velocità è assolutamente fondamentale, ovviamente. If/else sono molto più facili da leggere in caso di nidificazione di qualcosa di simile (c1)?(c2)?(c3)?(c4)?:1:2:3:4. E avendo grandi espressioni come argomenti della funzione è non divertimento.

    Anche tenere a mente che nidificati ternario espressioni di fare refactoring del codice, – debug o inserendo un mazzo di pratici printfs() in una condizione molto più difficile.

    • A proposito, interessante è stato che quando ho cercato di essere più intelligente di quanto il compilatore nel 3 > 2 > 1 del codice, e ‘ fallito in modo spettacolare, come mi aspettavo. Conclusione: Mai cercare di superare in astuzia il compilatore!
  3. 7

    L’unico beneficio potenziale per la ternario operatori pianura istruzioni se il mio punto di vista è la loro capacità di essere utilizzato per l’inizializzazione, che è particolarmente utile per const:

    E. g.

    const int foo = (a > b ? b : a - 10);

    Fare questo con un if/else blocco è impossibile senza l’uso di una funzione cal pure. Se vi capita di avere un sacco di casi di const cose come questa si potrebbe trovare un piccolo guadagno dal inizializzazione di un const correttamente su incarico con if/else. Misurare! Probabilmente non sarà nemmeno essere misurabili, però. La ragione per cui io tendo a fare questo perché da marcatura const il compilatore sa che quando faccio qualcosa più tardi che potrebbe/dovrebbe cambiare accidentalmente qualcosa a cui ho pensato è stato risolto.

    Efficacemente quello che sto dicendo è che l’operatore ternario è importante per const-correttezza e const la correttezza è una grande abitudine di essere in:

    1. Questo consente di risparmiare un sacco di tempo, lasciando che il compilatore che consente di individuare errori che si fanno
    2. Questo può potenzialmente consentire al compilatore di applicare altre ottimizzazioni
  4. 3

    Si assume che vi deve essere una distinzione tra i due, quando, in realtà, ci sono un certo numero di lingue, che rinunciare al “if-else” in favore di un “if-else” espressione (in questo caso, si può anche non avere l’operatore ternario, che non è più necessario)

    Immaginare:

    x = if (t) a else b

    Comunque, l’operatore ternario è un’espressione in alcuni linguaggi (C,C#,C++,Java,ecc), che fanno non hanno “if-else”, espressioni e così serve un ruolo distinto c’.

  5. 1

    Se siete preoccupati da un punto di vista delle prestazioni, quindi sarei molto sorpreso se c’è qualche differenza tra i due.

    Da un look ‘n feel prospettiva è soprattutto il basso per preferenze personali. Se la condizione è breve e il true/false parti sono brevi quindi un operatore ternario è bene, ma nulla di più tende a essere migliore in un if/else (a mio parere).

Lascia un commento