2010-04-10 12 views
5

Considerare il seguente codice dove restituisco double& e un string&. Funziona bene nel caso di un doppio ma non nel caso di una stringa. Perché il comportamento differisce?Restituzione di un riferimento in C++

In entrambi i i casi il compilatore non anche gettare la Warning: returning address of local variable or temporary come sto tornando un punto di riferimento.

#include <iostream> 
#include <string> 
using namespace std; 


double &getDouble(){ 
    double h = 46.5; 
    double &refD = h; 
    return refD; 
} 

string &getString(){ 
    string str = "Devil Jin"; 
    string &refStr = str; 
    return refStr; 
} 

int main(){ 
    double d = getDouble(); 
    cout << "Double = " << d << endl; 

    string str = getString(); 
    cout << "String = " << str.c_str() << endl; 

    return 0; 
} 

uscita:

$ ./a.exe 
Double = 46.5 
String = 
+0

Ho avuto un post simile e le risposte sono state molto utili. Inoltre, controlla i commenti http://stackoverflow.com/questions/2612709/why-does-this-object-wonk-out-get-deleted – brainydexter

risposta

15

non si dovrebbe mai restituire un riferimento a una variabile locale non importa quale sia il compilatore fa o non fa. Il compilatore può essere ingannato facilmente. non dovresti basare la correttezza del tuo codice su alcuni avvertimenti che potrebbero non essere stati attivati.

Il motivo per cui non è stato attivato qui è probabilmente che non si sta letteralmente restituendo un riferimento a una variabile locale, si sta restituendo una variabile che è un riferimento a una variabile locale. Il compilatore probabilmente non rileva questa situazione un po 'più complessa. Si rileva solo le cose come:

string &getString(){ 
    string str = "Devil Jin"; 
    return str; 
} 

Il caso del doppio è più semplice perché non comporta la costruzione e distruggendo un oggetto complesso così in questa situazione l'analisi di controllo del flusso del compilatore probabilmente ha fatto un lavoro migliore a rilevare l'errore.

+0

localmente alla funzione, ovviamente. hai il permesso di restituire un riferimento a qualsiasi cosa al di fuori del tuo campo di applicazione: dati dei membri, parametri di funzione presi come riferimento ecc. – wilhelmtell

+6

In realtà, penso che dice che l'avviso NON viene sparato anche nel caso del doppio. Quindi il compilatore è ingannato in entrambi i casi. La ragione per cui funziona con il doppio è probabile perché la posizione di h in pila non è stata sovrascritta. Prova questo: nel negozio principale d in un doppio e poi chiama un paio di altre funzioni, quindi stampa d. Scommetto che non viene fuori giusto. In tutti i casi, però, quello che fai è "comportamento indefinito". C'è una lezione eccellente lì: solo perché dà la risposta giusta non significa che sia fatta nel modo giusto. ;) –

6

Il riferimento a double si riferisce a un percorso che è ancora fisicamente in memoria ma non più nello stack. Lo stai cavando solo perché la memoria non è stata ancora sovrascritta. Mentre lo double è una primitiva, lo string è un oggetto e ha un distruttore che può cancellare la stringa interna a una lunghezza zero quando non rientra nell'ambito. Il fatto che tu non stia ottenendo rifiuti dalla tua chiamata a c_str() sembra supportarlo.

+1

Onestamente tutto ciò sembra una speculazione, e in realtà non importa. Quando si restituisce un riferimento a una variabile locale, il compilatore può fare tutto ciò che vuole.Se si ha voglia di fare una pausa e andare in cucina a farsi un panino, allora va bene anche per lo standard. Quindi la risposta è semplice: non restituire un riferimento a meno che la variabile non sia locale alla funzione. – wilhelmtell

+0

Ecco perché ho detto "farla franca". Non sto supportando il comportamento solo cercando di rispondere "perché?" –

+0

@wilhelmtell: Non è una speculazione, è ciò che accadrà. Il problema è una volta che si utilizza il valore restituito, poiché possono accadere tutti i tipi di cose brutte: la cosa migliore da fare è il programma segfaults; il peggio è che il tuo programma continua a funzionare fino a quando non si comporta misteriosamente o segfaults in seguito. – CMircea

1

GCC aveva un'estensione denominata Named Returns che consente di eseguire la stessa operazione, ma ha assegnato lo spazio all'esterno della funzione. Sfortunatamente non esiste più; Non sono sicuro del motivo per cui l'hanno estratto

+0

+1 per il riferimento storico, anche se non è più valido. E benvenuto in SO. –

0

Caso classico di un riferimento Dangling rispetto a C++. La doppia variabile non era su stack di chiamate mentre il riferimento di riferimento stava tentando di accedervi invocando il compilatore per impostare i flag di guardia. String ha tuttavia un meccanismo di Garbage Collection esplicito che consente al compilatore di trascurare lo scenario.

Problemi correlati