2014-04-06 12 views
5

Avere una classe che tiene un riferimento ci si aspetterebbe il seguente codice sicuro misero, ma compila:Perché la classe contiene un riferimento copiabile?

#include <iostream> 

struct ReferenceHolder 
{ 
    std::string& str; 

    ReferenceHolder(std::string& str) 
    : str(str) 
    {} 
}; 

// Why does this compile? 
ReferenceHolder f() { 
    std::string str = "Hello"; 
    return ReferenceHolder(str); 
} 

int main() { 
    ReferenceHolder h = f(); 
    std::cout << "Should be garbage: " << h.str << '\n'; 
    return 0; 
} 

compilatore: g ++ 4.7.2 (con -std = C++ 11)

Modifica: Perfino con costruttori -fno-elide che compila felicemente

+0

Apparentemente viene spostato. Non si compila se si cancella esplicitamente il costruttore di mosse. – jrok

+0

@jrok Vero, ma per quanto posso vedere è sia copiabile che mobile. – dyp

+0

È interessante notare che, in base alla presentazione della CPU Mill (Security talk), su questa architettura si otterrebbe un errore di segmentazione. –

risposta

7

Non c'è alcun problema con l'inizializzazione della copia della classe, come fa l'esempio: il nuovo riferimento è semplicemente inizializzato per fare riferimento allo stesso oggetto di quello vecchio. Naturalmente, si ottiene un comportamento indefinito quando la funzione return lascia penzolare il riferimento.

Il riferimento impedisce l'inizializzazione di default e l'assegnazione della copia; quindi la seguente piccola modifica non riuscirà per questi motivi:

ReferenceHolder h; // ERROR: can't default-initialise the reference 
h = f();   // ERROR: can't reassign the reference. 
1

Questo codice ha un comportamento non definito, vedere the classic answer from Eric Lippert.

Il riferimento in h è legato al riferimento nel valore restituito da f(), che è legato alla ReferenceHolder nell'espressione di ritorno, e quindi h riferimenti str da f() fuori della sua portata.

+0

Lo so. Vedi: "Dovrebbe essere spazzatura" –

+1

@ DieterLücking: comportamento non definito non significa "spazzatura", significa "qualsiasi cosa". – Mankarse

+1

In altre parole, il costruttore di copie predefinito copia solo ricorsivamente i membri (come sempre) e per i riferimenti, ciò significa semplicemente fare riferimento ai dati originali. L'unica cosa che rimane da affrontare è la tua aspettativa che il codice fallirà miseramente e che la stringa conterrà spazzatura, quando il comportamento indefinito non garantisce nessuna di queste cose. – Mankarse

Problemi correlati