2010-07-15 5 views
9

Una domanda di base che non sono sicuro della risposta. La funzione follow è valida?C++ return reference/stack memory

std::vector<int> & test_function() { 
    std::vector<int> x; 

    // do whatever 

    return x; 
} 

Se sì, perché? Il programma non dovrebbe cancellare x dalla pila dopo che la funzione è tornata? Grazie.

risposta

11

Il comportamento non è definito. Non si dovrebbero restituire riferimenti a variabili locali.

+1

Dannazione, bastonatemi! – Anthony

+1

Il codice che viene mostrato non contiene (da solo) alcun comportamento indefinito. L'UB si sarebbe verificato in un altro codice che chiama questa funzione. –

8

La funzione è ben formata (sintatticamente corretta), ma non appena la funzione restituisce, il riferimento restituito non è valido e non può essere utilizzato.

Per chiarire: il codice in questione fa non invoca un comportamento non definito. È possibile chiamare in modo sicuro questa funzione fino a quando non si utilizza il valore di ritorno, ad esempio, questo è valido:

test_function(); // ok 

Tuttavia, se si tenta di utilizzare il valore di ritorno (vale a dire, inizializzare un altro riferimento ad esso o copiare il referente in un altro oggetto), allora si invocherà un comportamento indefinito perché la durata del referente (l'oggetto x) sarà finita (x saranno distrutti quando la funzione restituisce perché è una variabile automatica):

std::vector<int>& vec = test_function(); // undefined 
std::vector<int> vec = test_function(); // undefined 
+0

Su una nota seria, se la struttura a cui si fa riferimento è solo una manciata di POD (nessun puntatore) o è una primitiva, se si tiene il normale stack frame e si copia il valore (non tenere un riferimento ad esso, quindi il secondo esempio qui), il valore locale originale andrà bene immediatamente dopo il ritorno ('mov esp, ebp; pop ebp;' frame stack locale non disturbato). I distruttori, tuttavia, vengono richiamati e i dati possono essere manipolati/modificati. Questo è il modo sbagliato di fare questo, però, e prevedere cosa accadrà, anche se indovinato con precisione in un posto non è portatile. –

+0

@jMerliN: anche per un oggetto di tipo POD, i risultati sono formalmente non definiti. La durata di vita di un POD termina quando termina la sua durata di archiviazione; per una variabile locale, questo è al punto che la funzione ritorna. L'utilizzo di un oggetto dopo la sua durata è un risultato in un comportamento indefinito. Questo forse "funziona" in pratica con gli oggetti di tipo POD? Forse, ma come dici tu, non è un comportamento su cui ci si dovrebbe basare. –

+0

Non si dovrebbe assolutamente fare affidamento su quando il multi threading diventa standard poiché la posizione dello stack frame potrebbe essere già stata riutilizzata da un altro thread (si noti che lo standard non definisce il modo in cui lo stack o l'heap sono implementati). –

0

Non puoi restituire un riferimento a una variabile locale per lo stesso motivo per cui non puoi restituire un POI nter a una variabile locale, perché al ritorno dalla funzione queste variabili locali sono deallocate e quindi il riferimento o il puntatore non è più valido.

2

Sì, è valido, ma se si tenta di utilizzare il valore restituito, si otterrà un comportamento non definito.