2012-03-06 4 views
5

ad esempio la funzione f definita in questo modo:Perché è possibile restituire una funzione per riferimento per una variabile locale e non per una variabile temporanea? C++

int f(int x){return x;} 

come sapete Non puoi assegnare un riferimento alla presente temporanea int:

int& rf=f(2);// this will give an error 

ma se ho ridefinito la mia funzione f come questo :

int& f(int x){return x;} 
f(2);// so now f(2) is a reference of x, which has been destroyed 

quindi la mia domanda è: come può il compilatore non consentire di creare un riferimento a un temp orario che sarà distrutto dopo la dichiarazione (nel primo caso). e d'altra parte ti permette di creare un riferimento f (2) a x mentre il compilatore sa che questo sarà distrutto dopo lo return.

+1

Questo è UB (beh, accedendo al riferimento, comunque) e qualsiasi compilatore sensato ti avviserà a riguardo. –

risposta

7

Tornando un riferimento a un locale è qualcosa che può essere difficile o impossibile per il compilatore di rilevare. Per esempio:

int & f() 
{ 
    int x; 
    extern int & g(int & x); 

    // Does this return a reference to "x"? 
    // The compiler has no way to tell. 
    return g(x); 
} 

Anche senza chiamare funzioni esterne, può ancora essere difficile da analizzare un flusso di programma complesso per dire se il riferimento restituito è un locale; piuttosto che cercare di definire ciò che conta come "abbastanza semplice" da diagnosticare, lo standard non richiede una diagnostica - afferma solo che fornisce un comportamento indefinito. Un buon compilatore dovrebbe dare un avvertimento, almeno in casi semplici.

Associare un riferimento temporaneo a un riferimento non const è qualcosa che il compilatore può facilmente rilevare, e quindi lo standard richiede una diagnostica per questo.

1

Perché, come specificato dallo standard, restituire un riferimento a una variabile temporanea da una funzione è un comportamento non definito.

Cosa c'è che non va è in realtà la definizione della funzione:

int& f(int x) 
{ 
    return x; 
} 
0

non è una buona idea per tornare con riferimento se non sei sicuro il riferimento stai tornando sarà ancora puntato verso qualcosa di valido.

in caso contrario, è previsto un comportamento non definito.

in quanto la variabile è locale, si può essere sicuri che teh di riferimento non è valido

+2

Poiché la variabile è locale, puoi essere sicuro che non è valido. –

1

È possibile associare il rvalore temporaneo a un riferimento const per prolungare la sua durata.

const int& rf=f(2); 
0

Il problema è che semanticamente non v'è alcuna differenza tra una variabile su una pila, o di una variabile sul mucchio ecc - Così il linguaggio non ha altra scelta, ma per consentire a questo, anche se è un comportamento indefinito. Nel primo esempio si ottiene un errore di compilazione facile, perché si sta tentando di associare un riferimento su una variabile temporanea, che può essere vietata dalla lingua.

+0

si lo capisco, ma perché funziona per il secondo esempio? e perché hai menzionato l'heap e non ho detto nulla sull'heap – AlexDan

+0

@AbdessamadBond C'è la risposta perché il tuo secondo esempio non funziona .. e ho menzionato l'heap, perché restituire un riferimento a una variabile sull'heap è ok (anche se probabilmente è cattivo stile). Semanticamente non c'è differenza tra una variabile sull'heap e una sullo stack, mentre c'è una differenza tra una variabile e un valore temporaneo. – cooky451

1

Per rifiutare il primo snippet di codice, il compilatore applica la regola semplice che non è possibile associare direttamente un riferimento temporaneo a un riferimento non const.

Per rifiutare il secondo, il compilatore potrebbe forse applicare una regola che l'istruzione return di una funzione che restituisce per riferimento non può essere il nome di una variabile automatica (incluso un parametro di funzione di valore per byte). Anche a me sembra una regola abbastanza facile.

Non so perché lo standard non specifica che farlo è mal formato. Non riesco a pensare a un uso valido per questo, ma forse al momento del primo standard avrebbe creato un onere eccessivo su qualche implementazione o altro. O forse si è ritenuto che fosse solo una mezza correzione e non ne valesse la pena (ci sono molti altri modi per creare un riferimento ciondolante, questo blocca solo uno di essi).

Il motivo per cui lo standard in genere non impedisce di creare un riferimento non const associato a un temporaneo è che ci sono occasioni in cui è OK. Ad esempio:

struct Foo { 
    static void set(Foo &f) { f.val = 0; } 
    int val; 
    int bar() { 
     set(*this); 
     return val; 
    } 
}; 

std::cout << Foo().bar() << "\n"; 

Qui Foo() è un temporaneo, e la linea set(*this) si lega ad un riferimento non const (ma non direttamente, esso utilizza un'espressione lvalue *this che si riferisce ad una temporanea alcune volte, ma non altre) . Non c'è nessun problema qui, il temporaneo sopravvive al riferimento. Quindi sarebbe inutilmente restrittivo che il linguaggio impedisca in qualche modo a qualsiasi temporaneo di essere associato a qualsiasi riferimento non const.