2013-03-14 12 views
7

Qualcuno può verificare che quanto segue sia un bug e spiegare perché? Penso di saperlo, ma non sono chiaro sui dettagli. (Il mio vero problema ha coinvolto un vettore di enumerazioni, non interi, ma non credo che dovrebbe importa.) Supponiamo che io ho il seguente codice:Riferimento all'elemento di vettore restituito da una funzione in C++

std::vector<int> f (void) { 
    std::vector<int> v; 
    v.push_back(5); 
    return v; 
} 

void g (void) { 
    const int &myIntRef = f()[0]; 
    std::cout << myIntRef << std::endl; 
} 

Sono corretto che myIntRef è subito un punto di riferimento penzoloni, perché il valore di ritorno di f viene salvato da nessuna parte nello stack?

Inoltre, la seguente è una correzione valida oppure è ancora un bug?

const int myIntCopy = f()[0]; // copy, not a reference 

In altre parole, è il risultato di ritorno di f() buttato via prima l'elemento 0a possono essere copiati?

+0

Sono solo curioso, ma c'è qualche ragione per usare un 'int const &' invece di un 'int' come variabile locale? –

+0

@JamesKanze: Forse per contrassegnare la variabile come 'const'? –

risposta

2

Sì, è davvero una cosa sbagliata. Quando si chiama: viene creata

return v; 

copia temporanea dell'oggetto v e

const int &myIntRef = f()[0]; 

inizializza il vostro riferimento con il primo elemento di questa copia temporanea. Dopo questa riga, la copia temporanea non esiste più, ovvero myIntRef è un riferimento non valido, il cui utilizzo produce il comportamento non definito .

Che cosa si dovrebbe fare è:

std::vector<int> myVector = f(); 
const int &myIntRef = myVector[0]; 
std::cout << myIntRef << std::endl; 

che (grazie a copia elisione) utilizza un operatore di assegnazione per inizializzare myVector oggetto utilizzando v senza copia di v in fase di creazione. In questo caso la durata del riferimento è pari alla durata dell'oggetto myVector, rendendolo un codice perfettamente valido.


E alla tua seconda domanda: "Inoltre, è la seguente un fix valido, o è ancora un bug"

const int myIntCopy = f()[0]; // copy, not a reference 

Sì, questo è un altro possibile soluzione. f()[0] accede al primo elemento della copia temporanea e utilizza il suo valore per inizializzare la variabile myIntCopy.E 'garantito che la copia del v restituito da f() esiste almeno fino a quando viene eseguito l'intera espressione, vedi C++ 03 di serie 12.2 oggetti temporanei §3:

oggetti temporanei vengono distrutte come l'ultimo passo valutare l'espressione completa (1.9) che (lessicalmente) contiene il punto in cui sono stati creati.

+0

Grazie mille. – user2170028

11

Questo è un bug. Alla fine dell'espressione completa const int &myIntRef = f()[0]; il vettore temporaneo verrà distrutto e la memoria verrà rilasciata. Qualsiasi utilizzo successivo di myIntRef è un comportamento non definito.

In alcune circostanze, il riferimento a un riferimento temporaneo può prolungare la durata del periodo temporaneo. Questo non è uno di questi casi, il compilatore non sa se il riferimento restituito da std::vector<int>::operator[] fa parte del temporaneo o un riferimento a uno int con durata di archiviazione statica o qualsiasi altra cosa, e non prolungherà la durata.

+0

Grande - grazie mille. – user2170028

+0

A proposito, ho aggiunto una domanda di follow-up, se ti senti così incline :-). – user2170028

+0

@ user2170028: la risposta alla domanda di follow-up è: Sì. Vedi la mia risposta :) – LihO