2009-10-04 13 views
6

Quando ho letto litb answer to this question, ho imparato che passare un array per riferimento ci consente di ottenere le sue dimensioni. Ho appena giocato po 'con il codice, e ho cercato di passare una "funzione" di riferimento e sorprendentemente (almeno per me), questo codice compila:Qualcuno potrebbe spiegare la differenza tra un "riferimento" e un "puntatore" in questo caso?

void execute(void (&func)()) // func is passed by reference! 
{ 
    func(); 
} 

C'è qualche differenza tra l'ultima funzione, e questo :

void execute(void (*func)()) // func is passed by pointer! 
{ 
    func(); 
} 

Ho provato utilizzando VC2008 e produce output diversi in ogni caso. La cosa strana è che il compilatore ottimizza il codice migliore in caso di un puntatore a funzione:

void print() 
{ 
    std::cout << "Hello References!"; 
} 
void execute(void (&func)()) // optimized 
{ 
    func(); 
} 
int main() 
{ 
    00291020 call print (291000h) 
} 
========================================= 
// In this case, the compiler removes all function calls in the code! 
void print() // optimized! 
{ 
    std::cout << "Hello Pointers!"; 
} 
void execute(void (*func)()) // optimized 
{ 
    func(); 
} 
int main() 
{ 
    002F1005 push offset string "Hello References!" (2F2124h) 
    002F100A push eax 
    002F100B call std::operator<<<std::char_traits<char> > (2F1150h) 
} 

Ci deve essere una differenza, anche se io non lo vedo, giusto?

Nota: il codice è stato compilato utilizzando VC2008, con /O2 e /Ot attivato.


EDIT :: Sono molto interessati circa l'eventuale differenza tra riferimenti alle funzioni e puntatori a funzione. Ho esaminato il codice assembly prodotto solo per vedere come viene tradotto in ogni caso.

+0

sono semplicemente interessati al comportamento ottimizzatori o in informazioni generali sulla funzione di riferimento? –

+0

@litb Sono davvero sorpreso di poter passare una funzione per riferimento. Sarebbe fantastico se tu avessi una spiegazione sulla differenza di funzionalità o altri aspetti dai puntatori di funzione :) – AraK

risposta

3

Per la differenza di lingua (mantenendo solo le dichiarazioni di funzione di seguito, dato che questo è ciò che è importante solo)

void execute(void (&func)()); 

void g(); 
int main() { 
    void (*fp)() = g; 
    execute(fp); // doesn't work 
    execute(&g); // doesn't work either 
    execute(g); // works 
} 

non funziona, perché vuole una funzione, non un puntatore a funzione. Per lo stesso motivo per cui la risposta dell'array rifiuta un puntatore, anche questo rifiuta un puntatore. Devi passare "g" direttamente.

Per i modelli, è importante anche

template<typename T> 
void execute(T &t) { T u = t; u(); } 

template<typename T> 
void execute(T t) { T u = t; u(); } 

Quei due sono molto diversi l'uno dall'altro. Se lo chiami con execute(g); come sopra, allora il primo tenterà di dichiarare una funzione e inizializzarla con t (riferimento a g). La funzione generata sarebbe simile a questa

void execute(void(&t)()) { void u() = t; u(); } 

Ora è possibile inizializzare riferimenti e puntatori a funzioni, ma naturalmente non funzioni se stesso. Nella seconda definizione, T verrà dedotta a un tipo di puntatore a funzione in base alla deduzione dell'argomento modello e passando una funzione lo convertirà implicitamente in quel tipo di parametro puntatore. Quindi tutto andrà bene.


non so il motivo per cui MSVC li tratta in modo diverso per inline - ma ho anche il sospetto che sia perché i riferimenti di funzione appaiono più raramente.

+0

Che dire di 'execute (* fp);', però - il quarto caso mancante :-) –

3

Non è un idioma comune, quindi potrebbe essere solo che il team VS non ha aggiunto una regola per ottimizzarlo.

3

ritengo sia dovuto al C++ standard 4.3:

Un lvalue di tipo funzione T può essere convertito in un rvalue di tipo “puntatore a T” Il risultato è un puntatore funzione .

+0

Citazione interessante. Ciò non significa che dopo aver convertito il riferimento alla funzione, in entrambi i casi dovrebbe essere prodotto lo stesso codice. So che questo è un dettaglio di implementazione, ma come potrebbe il compilatore ottimizzare il puntatore e non il riferimento (se viene convertito)? – AraK

-2

La differenza tra un riferimento (&) e un puntatore (*) è che il riferimento fornisce l'indirizzo della variabile o la posizione e il puntatore punta alla posizione in memoria dell'indirizzo memorizzato in esso.

int *pointer; 
int variable; 

pointer = &variable; // assigning the address of variable to pointer 

variable = 53; // value of variable 

cout << *pointer; // This should output the value of the address where is pointing, in this 
        // case 53, that is the value of variable to where is pointing. 

Possiamo concludere che il (& variabile) hanno l'indirizzo di quella posizione di memoria e * anyname indica l'indirizzo memorizzato nella sua memoria ...

+0

_ "il riferimento fornisce l'indirizzo della variabile o la posizione, e il puntatore punta alla posizione in memoria dell'indirizzo memorizzato in esso. "_ huh ... Penso che tu stia confondendo i riferimenti per l'indirizzo-dell'operatore. –

Problemi correlati