2011-10-28 2 views
31
if(a && b) 
{ 
    do something; 
} 

c'è la possibilità di valutare gli argomenti da destra a sinistra (b -> a)?Ordine di valutazione argomento "IF"?

se "sì", cosa influenza l'ordine di valutazione?

(sto usando VS2008)

+9

'if (b && a)' lo farà per voi. –

+1

Cosa sono 'a' e' b'? –

+0

prova se (b && a). prova questo link: http://msdn.microsoft.com/en-us/library/2bxt6kc4.aspx – CloudyMarble

risposta

37

L'ordine di valutazione è specificato dallo standard ed è left-to-right. L'espressione più a sinistra verrà sempre valutata per prima con la clausola &&.

Se vuoi b da valutare prima:

if(b && a) 
{ 
    //do something 
} 

Se entrambi gli argomenti sono i metodi e si desidera entrambi da valutare indipendentemente dal loro risultato:

bool rb = b(); 
bool ra = a(); 

if (ra && rb) 
{ 
    //do something 
} 
+3

questo è un sollievo ... per una volta C++ ha il comportamento predefinito corretto invece di uno sorprendentemente chiaro –

+3

@AviadRozenhek: hai ragione di essere spaventato perché in effetti è possibile che l'espressione 'b' sia valutata prima dell'espressione' a'. Perché ciò avvenga, tuttavia, l'operatore non deve essere l'operatore '&&' logico-e, ma un sovraccarico per i tipi definiti dall'utente.In questo caso l'ordine di valutazione degli argomenti non è specificato (e peggio di quello che non si può nemmeno aspettare un ordinamento reale perché la valutazione può anche essere "mescolata": un po 'di a, quindi alcuni di 'b', quindi più di 'a', poi ancora alcuni bit rimanenti di' b' e infine viene chiamato l'operatore personalizzato). – 6502

+0

Che succede se invece si utilizza '||'? _should_ rimane lo stesso a meno che alcune ottimizzazioni del compilatore non lo facciano, correggere @ 6502? – mdw7326

7

In questo caso, dal momento che si sta utilizzando &&, a sarà sempre essere valutati in primo luogo perché il risultato viene utilizzato per determinare se o non cortocircuitare l'espressione.

Se a restituisce false, quindi b non è autorizzato a valutare affatto.

+1

... a meno che l'operatore && non sia sovraccarico. Che è possibile, ma considerato come un cattivo design. – dalle

+0

Non ci ho pensato. Buon punto :) – Mysticial

+0

Sono certo che quanto segue è il caso, ma è sicuro fare qualcosa del genere: 'Obj * obj; if (obj && obj-> foo()) {...} ' Suppongo che controlli che wheter obj non sia NULL e solo se non è NULL, controllerà il risultato di' obj-> foo() ', destra? –

2

Valuterà da sinistra a destra e cortocircuiterà la valutazione se possibile (ad esempio, se una valutazione è falsa, non valuterà b).

Se si preoccupa dell'ordine in cui vengono valutati, è sufficiente specificarli nell'ordine di valutazione desiderato nella dichiarazione if.

+0

La domanda riguarda C++, non C# (anche se probabilmente hai ragione che entrambi fanno la stessa cosa, ispirati a ciò che fa C). –

+0

oops! Presumo che siano entrambi gli stessi come dici tu. –

44

Con C++ ci sono solo alcuni operatori che garantiscono l'ordine di valutazione

  • operator && valuta prima l'operando sinistro e se il valore è logicamente false, allora evita di valutare l'operando corretto. L'uso tipico è ad esempio if (x > 0 && k/x < limit) ... che evita problemi di divisione per zero.

  • operator || valuta prima l'operando sinistro e se il valore è logicamente true, quindi evita di valutare l'operando corretto. Ad esempio if (overwrite_files || confirm("File existing, overwrite?")) ... non chiederà conferma quando è impostato il flag overwrite_files.

  • operator , valuta prima l'operando sinistro e poi l'operando destro, restituendo il valore dell'operando destro. Questo operatore non viene usato molto spesso. Si noti che le virgole tra i parametri di una chiamata di funzione sono non gli operatori virgola e l'ordine di valutazione non è garantito.

  • ternario operatore x?y:z Esamina x prima, e poi a seconda del valore logico del risultato valuta o unicamente y o solo z.

Per tutti gli altri operatori l'ordine di valutazione non è specificato.

la situazione è in realtà peggiore, perché non è che l'ordine non è specificato, ma che non c'è nemmeno un "ordine" per l'espressione a tutti, e per esempio in

std::cout << f() << g() << x(k(), h()); 

è possibile che funzioni sarà chiamato nell'ordine h-g-k-x-f (questo è un po 'inquietante perché il modello mentale dell'operatore << trasmette in qualche modo l'idea di sequenzialità ma in realtà rispetta la sequenza solo nell'ordine i risultati sono messi nello stream e non nell'ordine i risultati sono calcolata).

Ovviamente le dipendenze del valore nell'espressione possono introdurre qualche garanzia di ordine; ad esempio nell'espressione precedente è garantito che sia k() sia h() verranno chiamati prima dello x(...) poiché i valori di ritorno di entrambi sono necessari per chiamare x.

Si noti inoltre che le garanzie per &&, || e , sono valide solo per operatori predefiniti. Se sovraccarichi questi operatori per i tuoi tipi, saranno in quel caso come normali chiamate di funzione e l'ordine di valutazione degli operandi non sarà specificato.

+1

Solo un pizzico, ma le dipendenze di valore impongono anche un ordine. In un'espressione come '(a + b) * c',' a' e 'b' devono essere valutati prima dell'aggiunta e l'aggiunta deve avvenire prima della moltiplicazione. Generalmente, questo effetto non è osservabile, ma se gli operatori sono sovraccarichi, potrebbe essere visibile. –

+0

@JamesKanze: Ok. Penso che sia ovvio per un linguaggio come il C++, ma ha aggiunto comunque una nota per quello. – 6502

3

Ogni valore di calcolo e lato effetto della prima (sinistra) argomentazione incorporato operatore logico AND & & e il built-in OR logico operatore || viene sequenziato prima di ogni calcolo del valore e dell'effetto collaterale del secondo argomento (a destra).

Leggi qui per una spiegazione più esaustiva delle regole stabilite: order evaluation

1

L'operatore && valuta sempre il suo operando a sinistra prima. Per esempio:

if (a && b) 
{ 
    //block of code 
} 

Se a è falso, allora b valutazione non sarà garantito.

Se si desidera b da valutare prima, e a solo se b è vero, è sufficiente scrivere l'espressione viceversa:

if (b && a) 
{ 
    //block of code 
}