2015-06-26 10 views
16

Per esempio:i = i ++; è indefinito. Anche i = foo (i ++) è indefinito?

int foo(int i) { return i; } 

int main() 
{ 
    int i = 0; 

    i = i++;  // Undefined 
    i = foo(i++); // ? 

    return 0; 
} 

Quale sarebbe l'attuale standard ISO C++ specificare per questo caso?

EDIT:

Ecco dove mi confondo:

Salvo quando diversamente indicato, valutazioni di operandi dei singoli operatori e di sottoespressioni delle singole espressioni sono non in sequenza.

Se un effetto collaterale su un oggetto scalare è non in sequenza rispetto a uno altro effetto collaterale sullo stesso oggetto scalare o un valore di calcolo utilizzando il valore dello stesso oggetto scalare, e non sono potenzialmente concomitanti (1.10), il comportamento è indefinito.

In tutti i casi, l'assegnazione viene sequenza dopo il valore calcolo degli operandi destro e sinistro, e prima che il valore calcolo dell'espressione assegnazione

ogni valutazione in funzione chiamante (comprese altre chiamate di funzione) che non è altrimenti specificatamente sequenziato prima o dopo l'esecuzione del corpo della funzione chiamata è sequenzialmente indeterminato con rispetto all'esecuzione della funzione chiamata.

Così sembra si potrebbe avere un calcolo del valore sul lato sinistro della cessione (appena i), e un effetto collaterale sul lato destro (la modifica di i da i++) che non sono in sequenza rispetto a vicenda.

EDIT2:

Per chi si trova qui, c'è davvero un grande spiegazione su sequenziamento che ho trovato here.

+5

'foo (i ++)' va bene, 'foo (i, i ++)' non è definito –

+0

foo (i ++) esegue una copia quindi non aumenta il suo valore se si tenta di stampare i dopo la chiamata di funzione. Ma foo (++ i) effettivamente lo fa. Guarda il gruppo –

+1

'pippo (i ++)' va bene, 'foo ((i, i ++))' va bene. – haccks

risposta

15

L'ultima frase nel tuo preventivo dice "non altrimenti specificamente sequenziato prima o dopo l'esecuzione del corpo della funzione chiamata" quindi la domanda è se l'incremento e l'assegnazione sono "altrimenti specificatamente sequenziati prima o dopo" il corpo della funzione.

1.9 [intro.execution] p15 ha la risposta:

Quando si chiama una funzione (se la funzione è in linea), ogni valore calcolo e lato effetto associato con qualsiasi espressione argomentazione, oppure con l'espressione postfissa che designa la funzione chiamata è sequenziata prima dell'esecuzione di ogni espressione o istruzione nel corpo della funzione chiamata.[Nota: I calcoli del valore e gli effetti collaterali associati alle diverse espressioni di argomento sono stati annullati. - nota end]

Quindi l'incremento di i accade prima che il corpo della funzione, e l'assegnazione di i accade dopo la funzione ritorna, quindi è perfettamente definiti.

Nella terminologia pre-C++ 11, la chiamata di funzione introduce un punto di sequenza tra l'incremento e l'assegnazione.

+0

Puoi controllare la mia modifica? Per l'assegnazione: "l'assegnazione è sequenziata dopo il calcolo del valore degli operandi di destra e di sinistra". Quindi potresti avere un calcolo del valore sul lato sinistro del compito, con solo 'i'. Quindi si può avere 'i ++' valutato prima della chiamata di funzione 'foo'. Ciò si tradurrebbe in un calcolo del valore su 'i' e un effetto collaterale dall'incremento che sono in successione l'uno rispetto all'altro, che è un comportamento indefinito. – Justin

+0

Dallo standard: "calcolo dei valori (compresa la determinazione dell'identità di un oggetto per la valutazione glvalue e il recupero di un valore precedentemente assegnato a un oggetto per la valutazione del valore nominale)." – Justin

+0

La chiave è che non esiste alcun effetto collaterale per il calcolo del valore della parte sinistra, e il valore dell'LHS non è necessario. È una valutazione lvalue, quindi determina solo l'identità dell'oggetto. L'effetto collaterale si verifica solo dopo il ritorno della funzione, e ciò deve avvenire dopo la valutazione dell'argomento della funzione. "Se ** un effetto collaterale su un oggetto scalare ** è ingiustificato rispetto a __un altro effetto collaterale sullo stesso oggetto scalare __ oa un calcolo del valore ** utilizzando il valore dello stesso oggetto scalare **, e non sono potenzialmente concomitanti (1.10), ** il comportamento non è definito. ** " –

11

i = foo(i++); va bene, perché i++ viene eseguito prima che venga chiamato foo(). Viene eseguita una copia di i, quindi viene incrementato i, quindi la copia viene passata a foo(). E 'lo stesso di fare questo in modo esplicito:

int tmp = i++; 
i = foo(tmp);