2016-05-07 12 views
5

Durante l'apprendimento del C++, mi è stato detto che se si desidera che più classi facciano riferimento allo stesso oggetto, è necessario fornire un puntatore all'oggetto. In Modern C++, probabilmente interpreterei questo come l'oggetto essendo un unique_ptr e le classi che contengono puntatori non-own-raw.Devo memorizzare i riferimenti nelle classi in C++?

Recentemente, il mio mentore al lavoro ha suggerito di utilizzare solo i puntatori quando si prevede di avere il punto di archiviazione su un oggetto diverso o null a un certo punto. Invece, dovresti memorizzare i riferimenti nelle classi.

Le variabili membro di riferimento sono una cosa che non ho mai visto prima, quindi cercavo consigli su quali fossero le preoccupazioni ... Ha senso ... Stai dicendo che questo riferimento non è mai considerato null ... Immagino che la preoccupazione sarebbe allora che non si potesse/check/per null. Dovrebbe essere un invariante della tua classe ...

Che ne dici di come questo si applica all'uso dei riferimenti per il polimorfismo?


Update: La risposta che ho selezionato copre le mie domande abbastanza bene, ma ho pensato di chiarire per i lettori futuri. Quello che stavo veramente cercando era un'idea delle conseguenze dell'uso di un riferimento piuttosto che di un puntatore come membro della classe. Mi rendo conto che il modo in cui la domanda è stata formulata ha fatto sembrare più che stavo cercando opinioni sull'idea.

+1

Sì, Non è possibile controllare per nulla, ma il riferimento può anche non essere nulla (a meno che non si tenta vero duro per essere). Una cosa a cui devi pensare è che i dati di riferimento-i membri devono essere inizializzati dal costruttore della classe. Hai una domanda più concreta? –

+0

Dovresti essere più concreto, questa domanda è molto aperta. Direi che quello che dice il tuo mentore ha molto senso, se non hai intenzione di cambiare dove "puntatore/riferimento" punta/si riferisce, dovresti usare i riferimenti. In questo modo si ottengono problemi null in fase di compilazione. – perencia

+0

I usano generalmente membro T e di esprimere un rapporto permanente per la durata di questo * * oggetto e l'uso T * quando il cui scopo è variabile/annullabile. – Galik

risposta

4

Devo memorizzare i riferimenti nelle classi in C++?

sì, perché no. Questa domanda è IMO "principalmente basata sull'opinione pubblica", quindi la mia risposta si basa sulla mia esperienza personale.

Uso i riferimenti dei membri quando non ho bisogno di ciò che i puntatori hanno da offrire, in questo modo limito la possibilità che la mia classe venga erroneamente utilizzata. Ciò significa tra l'altro possibilità di legare un nuovo valore, assegnare nullptr, non puoi prendere il puntatore come riferimento, non puoi usare aritmetica di riferimento - queste caratteristiche mancano nei riferimenti. Dovresti anche ricordare che il riferimento non è un tipo di oggetto, questo significa tra l'altro che se metti un riferimento come struct member, allora non è più POD - i.e. non puoi usare memcpy su di esso.

Si dovrebbe anche ricordare che per le classi che hanno un membro di riferimento non statico, il compilatore non genererà i costruttori impliciti.

Per me questo significa che i riferimenti come membri variabili sono per lo più utili quando la classe è una sorta di wrapper o un titolare. Di seguito è riportato un esempio che mostra anche un'implementazione alternativa utilizzando il tipo di membro puntatore. Questa implementazione alternativa non offre alcun vantaggio aggiuntivo a quello di riferimento e consente solo di introdurre il comportamento non definito.

struct auto_set_false { 
    bool& var; 
    auto_set_false(bool& v) : var(v) {} 
    ~auto_set_false() { var = false; } 
}; 

struct auto_set_false_ptr { 
    bool* var; 
    auto_set_false_ptr(bool* v) : var(v) {} 
    ~auto_set_false_ptr() { *var = false; } 
}; 

int main() 
{ 
    // Here auto_set_false looks quite safe, asf instance will always be 
    // able to safely set nval to false. Its harder (but not imposible) to 
    // produce code that would cause Undefined Bahaviour. 
    bool nval = false; 
    auto_set_false asf(nval); 

    bool* nval2 = new bool(true); 
    auto_set_false_ptr asf2(nval2);  
    // lots of code etc. and somewhere in this code a statement like: 
    delete nval2; 
    // UB 
} 
0

I riferimenti IMO funzionano come puntatori.

L'unica differenza è in dynamic_cast: un cast non riuscito produce un punto nullo con puntatori e genera un'eccezione con riferimenti.

+0

E il compito? E la costruzione predefinita? – juanchopanza

+0

@juanchopanza influenzano il polimorfismo? – granmirupa

+0

Sono due cose in cui i riferimenti differiscono dai puntatori e che devono essere considerati al momento di decidere se disporre di membri di dati di riferimento. – juanchopanza

0

I riferimenti sono molto meglio di puntatori a causa di una ragione: non c'è bisogno di giocare con i null. Un riferimento non può essere nullo ed è un grande valore non dover controllare i valori nulli.

La piccola difficoltà è che è necessario assegnare un membro di riferimento in un costruttore. Ma puoi sicuramente cambiarlo in seguito ad altri valori non nulli che puntano a un oggetto di una classe del membro o sottoclasse di questa classe. Quindi supporta l'ereditarietà come fanno i puntatori.

1

Generalmente non è una buona idea memorizzare i riferimenti in una classe perché la classe non può essere costruita in modo predefinito, copia assegnata, spostamento assegnato e il membro non può essere modificato (il riferimento non può essere rimbalzo).

che rende la classe uncopieable. Pertanto non può essere copiato, spostato o inserito nella maggior parte dei contenitori. La soluzione molto più flessibile e meno sorprendente è quella di memorizzare un puntatore o uno std :: refernce_wrapper.

+0

Il membro può essere modificato. Altre parti sono oggetto di discussione. Non è una buona idea solo da un certo punto di vista. Sono d'accordo che la classe può essere meno adatta all'utilizzo con i contenitori, ma std :: reference_wrapper che hai citato risolve questo problema. –

+0

@ Andrzej Forse dovrei riformulare/essere più specifico. Quello che intendevo è che il riferimento non può essere rimbalzato. – Thomas

Problemi correlati