2014-12-16 11 views
6

So che in C++ 11 la semantica del movimento è stata implementata nei contenitori STL per evitare oggetti temporanei. E la gente dice che ora è perfetto scrivere funzioni che tornano di valore. Ma ho delle confusioni sulla terra quante volte le copie sono effettivamente evitate. Si prega di consultare il seguente esempio:I container STL spostano la semantica e restituiscono per valore: quante volte la copia viene evitata?

vector<int> myVector() { 
    vector<int> res; 
    res.push_back(4); 
    res.push_back(5); 
    return res; 
} 

vector<int> v = myVector(); 

mia comprensione è che in C++ 03, myVector restituisce una copia di res (4, 5 copiato una volta), in sede di valutazione vector<int> v = myVector();vector<int> 's costruttore di copia vector<int>(const vector<int> &) viene richiamato (4 , 5 copiati due volte). Tuttavia in C++ 11 con la semantica del movimento, voglio sapere quale copia di 4 e 5 viene evitata? entrambi? L'ottimizzazione del valore di ritorno è anche invocata per ridurre il tempo di copia 4 e 5?

+2

In C++ 03, sono due copie, entrambe soggette ad elisione. In C++ 11, sono due mosse, entrambe soggette all'elisione. –

+0

Perché ci sono due mosse? – Allanqunzi

+0

La stessa ragione per cui ci possono essere due copie in C++ 03 - uno spostamento da 'res' nel valore di ritorno, e quindi uno spostamento da quello in' v'. –

risposta

4

Ci sono due copie in C++ 03 e due mosse in C++ 11.

Sia in C++ 03 che in C++ 11 la copia/le mosse sono soggette a elision e, come tale (in un esempio come questo) è probabile che non si verifichi alcuna copia/spostamento.

vector<int> myVector() { 
    vector<int> res; 
    res.push_back(4); 
    res.push_back(5); 
    return res;// <- Here we construct the return value with res 
} 

// here we construct v with the return value of myVector: 
vector<int> v = myVector(); 

l'elisione fuori dalla res nel valore di ritorno di myVector è un po 'fragile. In C++ 11, il move che potrebbe verificarsi se elision fallisce sarà quasi altrettanto libero (come non fare nulla) - 3 copie puntatore e 3 cancella puntatore. In C++ 03, la copia che potrebbe verificarsi se elision fallisce può essere costosa (allocazione di memoria e copie O (n)).

Elision è il nome dell'operazione che i compilatori possono eseguire in determinate circostanze in cui due valori vengono trasformati in uno solo, anche se tale trasformazione causerebbe un cambiamento nel comportamento (cioè, fallisce il test as-if).

Quando ciò accade, il valore combinato ha una durata dell'unione delle due vite.

Nel caso precedente, la variabile locale res e il valore di ritorno myVector() possono essere eliminati dalla regola NRVO (denominata ottimizzazione del valore di ritorno). Il valore di ritorno di myVector può essere eliminato in v in quanto è una dichiarazione del modulo A a = b dove b è un'espressione che risulta in un valore anonimo (il nome di tali valori anonimi è stato modificato da C++ 03 a C++ 11 in modo Non lo userò), in particolare il valore di ritorno di myVector().

Ciò causa la durata di vita di resv e il valore di ritorno di myVector() da unire in una durata di un valore. In pratica, ciò che accade è res viene inserito direttamente nel punto in cui deve andare il valore di ritorno di myVector() (in base alla convenzione di chiamata), e così è v e la distruzione è di questo valore combinato saltato fino a quando v non è più disponibile, come è in costruzione nell'istruzione return e su v = myVector().

In altre parole, v viene creato direttamente in myVector.

+0

Quindi nessun distruttore sarà chiamato fino a quando v non viene distrutto? – Allanqunzi

+1

@ user2345484 forse. Elision è ammesso dallo standard, non garantito. (In pratica, puoi pronosticare quando accadrà). Se si verificano entrambi i casi di elisione, sì, esiste un solo valore con una vita, e non viene distrutto finché 'v' non rientra nell'ambito. Ora, 'v' potrebbe essere eliso in un'altra variabile, nel qual caso la distruzione sarebbe ancora più tardi. – Yakk

Problemi correlati