2010-08-09 10 views
7

Recentemente ho visto un pezzo di codice in comp.lang.C++ moderato restituendo un riferimento di un intero statico da una funzione. Il codice è stato qualcosa di simileOttimizzazione prematura o sono pazzo?

int& f() 
{ 
    static int x; 
    x++; 
    return x; 
} 

int main() 
{ 
    f()+=1; //A 
    f()=f()+1; //B 
    std::cout<<f(); 

} 

Quando il debug l'applicazione che utilizza il mio fresco debugger di Visual Studio che ho visto una sola chiamata alla dichiarazione A e indovinate un po 'sono rimasto scioccato. Ho sempre pensato che i+=1 fosse uguale a i=i+1 quindi f()+=1 sarebbe uguale a f()=f()+1 e vedrei due chiamate allo f(), ma ne ho visto solo uno. Che diamine è questo? Sono pazzo o il mio debugger è impazzito o si tratta di un risultato di ottimizzazione prematura?

+4

'static int x' non è inizializzato. –

+1

Questo non è correlato alla domanda, però. – BjoernD

+1

@Rambo: Penso che tu stia parlando di questo thread: http://groups.google.com/group/comp.lang.c++.moderated/browse_thread/thread/566222d9b756ecc5/3279970278f46946 –

risposta

27

Questo è ciò che dice Lo Standard su += e gli amici:

5.17-7: Il comportamento di un'espressione del PO modulo E1 = E2 è equivalente a E1 = E1 E2 op salvo che E1 è valutata solo una volta. [...]

Quindi il compilatore è proprio su questo.

+4

Nice find. _______________ :-) –

10

i+=1 è funzionalmente uguale a i=i+1. In realtà è implementato in modo diverso (in pratica, è progettato per sfruttare l'ottimizzazione del livello della CPU).

Ma essenzialmente il lato sinistro viene valutato solo una volta. Produce un valore non const-l, che è tutto ciò di cui ha bisogno per leggere il valore, aggiungerne uno e scriverlo di nuovo.

Ciò è più evidente quando si crea un operatore sovraccarico per un tipo personalizzato. operator+= modifica l'istanza this. operator+ restituisce una nuova istanza. In genere è consigliabile (in C++) scrivere oop + = first, e quindi scrivere op + in termini di esso.

(Nota: questo è valido solo per C++, in C#, op+= è esattamente come si presume:. A breve portata di mano per op+, e non si può creare il proprio op + = E viene creata automaticamente per voi fuori dalla Op +)

9

Il tuo pensiero è logico ma non corretto.

i += 1; 
// This is logically equivalent to: 
i = i + 1; 

Ma logicamente equivalente e identico non sono gli stessi.
Il codice dovrebbe essere visto come simile a questo:

int& x = f(); 
x += x; 
// Now you can use logical equivalence. 
int& x= f(); 
x = x + 1; 

Il compilatore non fare due chiamate di funzione a meno che non esplicitamente mettere due chiamate di funzione nel codice. Se hai effetti collaterali nelle tue funzioni (come fai tu) e il compilatore ha iniziato ad aggiungere ulteriore difficoltà per vedere le chiamate implicite, sarebbe molto difficile capire realmente il flusso del codice e quindi rendere molto difficile la manutenzione.

3

f() restituisce un riferimento al numero intero statico. Poi += 1 aggiunge uno in questa posizione di memoria – non c'è bisogno di chiamare due volte nella dichiarazione A.

0

In ogni lingua che ho visto che supporta un operatore + =, il compilatore valuta l'operando del lato sinistro una volta per ottenere un tipo di indirizzo che viene poi utilizzato sia per leggere il vecchio valore sia per scrivere il nuovo. L'operatore + = non è solo zucchero sintattico; come si nota, può raggiungere una semantica dell'espressione che sarebbe scomoda da raggiungere con altri mezzi.

Per inciso, le istruzioni "With" in vb.net e Pascal hanno entrambe una funzione simile. Una dichiarazione come:

 
' Assime Foo is an array of some type of structure, Bar is a function, and Boz is a variable. 
    With Foo(Bar(Boz)) 
    .Fnord = 9 
    .Quack = 10 
    End With 
calcolerà l'indirizzo di Foo (Bar (Boz)), quindi imposta due campi di quella struttura sui valori nove e dieci. Sarebbe equivalente in C per

 
    { 
    FOOTYPE *tmp = Foo(Bar(Boz)); 
    tmp->Fnord = 9; 
    tmp->Quack = 10; 
    } 

ma vb.net e Pascal non esporre il puntatore temporaneo. Mentre si potrebbe ottenere lo stesso effetto in VB.net senza utilizzare "With" per contenere il risultato di Bar(), l'uso di "With" consente di evitare la variabile temporanea.

+0

Apparentemente ad es. C# valuta l'LHS due volte, come sottolinea James nella sua risposta. –

Problemi correlati