2014-09-17 16 views
9
std::unique_ptr<int> ptr() { 
    std::unique_ptr<int> p(new int(3)); 
    return p; // Why doesn't this require explicit move using std::move? 
} // Why didn't the data pointed to by 'p' is not destroyed here though p is not moved? 

int main() { 
    std::unique_ptr<int> a = ptr(); // Why doesn't this require std::move? 
    std::cout << *a; // Prints 3. 
} 

Nel codice precedente, la funzione ptr() restituisce una copia di p. Quando lo p esce dal campo di applicazione, i dati "3" dovrebbero essere eliminati. Ma come funziona il codice senza alcuna violazione di accesso?Come può un valore unique_ptr essere restituito dal valore senza std :: move?

+5

In realtà utilizza il 'std :: unique_ptr <>' [s move constructor] (http : //en.cppreference.com/w/cpp/memory/unique_ptr/unique_ptr). –

+4

Vedere [questa domanda correlata] (http://stackoverflow.com/questions/4316727/returning-unique-ptr-from-functions). E chi ha chiuso questo come un capriccio di "comportamento indefinito" ha bisogno di un caffè. –

+3

Questo è chiamato [copia elision] (http://stackoverflow.com/questions/12953127/what-are-copy-elision-and-return-value-optimization) –

risposta

14

Ciò è definito nello standard C++ 11, § 12,8/32:

Quando i criteri di elisione un'operazione di copia sono soddisfatte o sarebbero soddisfatte risparmi per il fatto che l'oggetto di origine sia un parametro di funzione, e l'oggetto da copiare sia designato da un lvalue, la risoluzione di sovraccarico per selezionare il costruttore per la copia viene eseguita per la prima volta come se l'oggetto fosse designato da un valore ....

(sottolineatura mia). In italiano semplice, significa che il lvalue p può essere considerato come un rvalue quando si tratta di risoluzione di sovraccarico, perché è un candidato per copia elision. Ciò a sua volta significa che il costruttore di movimento viene rilevato in risoluzione di sovraccarico (in realtà, la copia di spostamento viene probabilmente eliminata in ogni caso)

6

Poiché return di certe espressioni quali variabili automatiche locali, sono esplicitamente definite per restituire un spostato oggetto, se l'operatore è possibile il trasferimento.

Quindi:

return p; 

è più o meno simile a:

return std::move(p); 

Ma si noti che questo non funzionerà, per esempio con una variabile globale.

std::unique_ptr<int> g(new int(3)); 
std::unique_ptr<int> ptr() { 
    return g; // error!!! 
} 
+0

Questo non è generalmente vero. Si applica solo nella situazione in cui 'p' si qualifica per copia elisione. –

+0

@MattMcNabb: che è su ogni espressione 'return' con valore. E pochi altri posti. – rodrigo

+0

@rodrigo No, non è così semplice. Le condizioni per copia elision sono più complicate di quelle (sfortunatamente!) – juanchopanza

Problemi correlati