2013-03-10 9 views
7

Capisco che quando gli oggetti vengono restituiti in base al valore di una funzione, vengono chiamati i loro costruttori di copia. Se una classe ha un costruttore di copie cancellato, la restituzione per valore fallirà.Perché il costruttore di copie non viene chiamato quando restituisce un valore di inizializzazione di un oggetto con valore di lista?

struct X { 
    X(const X &) = delete; 
}; 

X f() { 
    return X{}; 
} 

error: call to deleted constructor of 'X'

C++ 11 ci dà extended-inizializzatori. E ho letto da qualche parte su un SO post che questo

X f() { 
    return {}; 
} 

è lo stesso di

X f() { 
    return X{}; 
} 

Allora, perché non il codice qui sotto mi danno un errore? Passa e ho anche arrivare a chiamare la funzione di principale: viene riportato

struct D { 
    D(const D &) = delete; 
}; 

D f() { return {}; } 

int main() 
{ 
    f(); 
} 

Here is a demo. Nessun errore. Lo trovo strano perché credo che il costruttore di copia debba essere chiamato. Qualcuno può spiegare perché non viene dato alcun errore?

+0

Cosa succede se elimini il costruttore di mosse? C++ 11 afferma che sarà usato se disponibile. –

+0

È interessante notare che non riesco a ottenere il codice da compilare su gcc 4.7.2 o uno snapshot 4.8. [Demo] (http://ideone.com/L94cwe). – juanchopanza

+0

@CrazyEddie Quando lo elimino viene indicato l'errore. Wow, è stato inaspettato. Mente postare che come risposta? –

risposta

12

e ho letto da qualche parte su un SO post che questo [...] è la stessa [...]

Si sbagliavano. Sono simili, ma non uguali.

Utilizzando la lista di controventi, è possibile inizializzare il valore di ritorno sul posto. Se crei un temporaneo, ciò che stai facendo è creare il temporaneo e quindi copiarlo nel valore di ritorno. Qualunque compilatore degno di questo nome lo eliderà, ma il costruttore di copie deve ancora essere accessibile.

Tuttavia, poiché la lista di inizializzazione rinforzata inizializza il valore di ritorno sul posto, non è necessario accedere al costruttore di copie.

dalla norma, sezione 6.6.3, p2:

Un'istruzione ritorno con a-init-list controventata inizializza l'oggetto o riferimento da restituire dalla funzione copiando-list-inizializzazione (8.5 .4) dall'elenco di inizializzazione specificato.

Si noti che "inizializzazione della lista di copia" non è simile a "inizializzazione della copia"; non esegue alcuna copia e pertanto non richiede un costruttore di copia accessibile. L'unica differenza tra "inizializzazione della lista di copia" e "inizializzazione della lista diretta" è che il primo si bloccherà sui costruttori explicit.

+0

Quindi stai dicendo che, se in una dichiarazione di ritorno hai usato una lista di init rinforzata, praticamente forza copia/sposta elision? –

+1

@SethCarnegie: No. Sto dicendo che se si utilizza una lista di init rinforzata, non c'è * nessuna copia *. Copia elision richiede ancora un costruttore di copia accessibile; braced-init-lists inizializza il valore di ritorno sul posto, senza un'operazione di copia/spostamento. –

+0

Oh, questo è interessante, non lo sapevo. Potresti citare la parte dello standard che lo specifica? –

Problemi correlati