2011-11-14 32 views
9
class x 
{ 
    int a; 
public: 
    x() 
    { 
     cout<<"\n\ndefault constructor"; 
    } 
    x(x& obj) 
    { 
     cout<<"\n\ncopy constructor"; 
    } 
    x fun() 
    { 
     x ob; 
     return ob; 
    } 
}; 
int main() 
{ 
    x ob1; 
    x ob2=ob1.fun(); 
    return 0; 
} 

inizialmente, questo codice ha dato un errore "nessuna funzione di corrispondenza per la chiamata a 'x :: x (x)'", quando ho cambiato il costruttore di copia perconst nel costruttore di copia in C++

x(const x& obj) 
{ 
    cout<<"\n\ncopy constructor"; 
} 

l'uscita diventa

predefinita costruttore

predefinita costruttore
ancora il costruttore di copia non è in esecuzione .... perché?

+0

http://stackoverflow.com/questions/1932700/copy-constructor-not-called-but-compiler-complains-that-theres-no – Mat

risposta

13

Questo viene chiamato copy-elision eseguito dal compilatore e consentito dalle specifiche del linguaggio.

Vedere questa voce wiki:

Per quanto riguarda il motivo per cui la versione non-const sta dando errore di compilazione perché obj1.fun() ritorno un oggetto temporaneo che non può essere legato a riferimento non-const, ma può legarsi al riferimento const, quindi la versione const viene compilata correttamente. Dopo averlo creato come riferimento const, viene utilizzato solo per il controllo semantico, ma il compilatore ottimizza il codice, eliminando la chiamata al copy-constructor.

Tuttavia, se lo si compila con l'opzione -fno-elide-constructors con GCC, la copia-elisione non verrà eseguita e verrà chiamato il costruttore della copia. Il GCC doc dice

-fno-Elide, costruttori

Lo standard C++ permette un'implementazione di omettere la creazione di un temporaneo che viene utilizzato solo per inizializzare un altro oggetto dello stesso tipo. Specificare questa opzione disattiva quell'ottimizzazione e obbliga G ++ a chiamare il costruttore di copie in tutti i casi.

+1

Ottima risposta! Grazie. – russoue

1

I valori temporanei sono valori validi e non sono associati a riferimenti non costanti. Pertanto, ob1.fun() non può essere associato al costruttore x::x(x&).

Tuttavia, rvalues ​​fare legano a costanti riferimenti.

Per quanto riguarda il motivo per cui non c'è nessuna uscita: Il costruttore di copia è un caso speciale nella norma, e il compilatore è permesso di elidere le chiamate costruttore di copia, anche se il costruttore di copia ha effetti collaterali. Tuttavia, la costruzione deve essere ancora valida! Un altro esempio è se hai dichiarato il costruttore di copie explicit - sarebbe comunque stato elidato, ma il tuo codice sarebbe errato.

In GCC è possibile pronunciare -fno-elide-constructors per riportare il costruttore.

3

Il compilatore ha deciso di ottimizzare la costruzione della copia come consentito, anche quando ha accettato l'argomento con riferimento const.

1

Il primo errore era dovuto al fatto che stava tentando di utilizzare il gestore di copie con un oggetto temporaneo.

ob1.fun(); // This returns an x by value 

Così, quando lo si utilizza sente

x ob2=ob1.fun();  // You are passing it by value which requires a local temporary 
// This is equivalent to this: 
x ob2(obj1.fun()); // So it is trying to do a copy construction. 

provvisori possono essere associati solo per i riferimenti const. Quindi non riesce a compilare.

Dopo aver risolto il problema (con il temporaneo) ora è possibile utilizzare il costruttore di copie. Ma al compilatore è permesso di ottimizzarlo, se possibile. Non è stato possibile ottimizzarlo perché non era nemmeno consentito utilizzarlo nella prima versione.

1

La chiamata del costruttore di copie è stata saltata a causa della copia dell'elisione dell'elisione. Non è possibile fare affidamento su alcun comportamento osservabile nel costruttore di copie come le istruzioni di stampa. Se vuoi vedere l'output da esso, prova a disabilitare le ottimizzazioni.

Problemi correlati