Domanda

Questo è un esempio semplificato per illustrare la domanda:

class A {};

class B
{
    B(A& a) : a(a) {}
    A& a;
};

class C
{
    C() : b(a) {} 
    A a;
    B b; 
};

Quindi B è responsabile per l'aggiornamento di una parte di C. Ho eseguito il codice tramite pelucchi e whinged circa il membro di riferimento: pelucchi # 1725 . Questo parla di prendersi cura nel corso di copia e le assegnazioni che è abbastanza giusto di default, ma la copia di default e l'assegnazione è anche male con i puntatori, quindi c'è poco vantaggio c'è.

cerco sempre di usare i riferimenti dove posso dato puntatori nudi introdurre uncertaintly su chi è responsabile per l'eliminazione di tale puntatore. Preferisco incorporare oggetti per valore ma se ho bisogno di un puntatore, io uso auto_ptr nei dati membro della classe che possiede il puntatore, e passare l'oggetto intorno come riferimento.

Sono in genere utilizzare solo un puntatore a dati utente quando il puntatore potrebbe essere nullo o potrebbe cambiare. Ci sono altre ragioni per preferire puntatori oltre riferimenti per i membri di dati?

E 'vero dire che un oggetto contenente un riferimento non dovrebbe essere assegnabili, dal momento che un riferimento non deve essere cambiato una volta inizializzato?

È stato utile?

Soluzione

Evitare i membri di riferimento, in quanto limitano ciò che l'implementazione di una classe può fare (tra cui, come si parla, che impediscono l'esecuzione di un operatore di assegnazione) e fornire benefici a ciò che la classe in grado di fornire.

problemi Esempio:

  • si è costretti a inizializzare il riferimento nella lista initialiser di ogni costruttore: non c'è modo di fattore questo di inizializzazione in un'altra funzione ( fino a C ++ 0x, comunque modifica C ++ ora ha costruttori delega )
  • il riferimento non può essere rimbalzo o essere nullo. Questo può essere un vantaggio, ma se il codice mai bisogno di cambiare per consentire rilegatura o per gli Stati ad essere nullo, tutti gli usi degli Stati necessario modificare
  • a differenza dei membri del puntatore, i riferimenti non possono essere facilmente sostituiti da puntatori intelligenti o iteratori come refactoring potrebbe richiedere
  • Ogni volta che viene utilizzato un riferimento sembra che tipo di valore (operatore . ecc), ma si comporta come un puntatore (può ciondolare) - così per esempio Style Guide Google scoraggia

Altri suggerimenti

La mia regola empirica:

  • Usa un membro di riferimento quando si desidera che la vita del vostro oggetto per essere dipendente dalla vita degli altri oggetti : è un modo esplicito per dire che non si consente l'oggetto deve essere in vita senza un'istanza valida di un'altra classe - a causa di alcuna assegnazione e l'obbligo di ottenere l'inizializzazione riferimenti tramite il costruttore. E 'un buon modo di progettare la vostra classe senza assumere nulla è esempio di essere membro o meno di un'altra classe. solo supporre che le loro vite sono direttamente collegate ad altre istanze. Esso consente di cambiare in seguito come si utilizza l'istanza della classe (con il nuovo, come istanza locale, come un membro della classe, generato da un pool di memoria in un manager, ecc.)
  • Usa puntatore in altri casi : Quando si desidera il membro per essere modificata successivamente, utilizzare un puntatore o un puntatore const per essere sicuri di leggere solo l'istanza appuntito. Se questo tipo dovrebbe essere copiabile, non è possibile utilizzare i riferimenti in ogni caso. A volte è anche necessario inizializzare il membro dopo una chiamata di funzione speciale (init () per esempio) e poi semplicemente non hanno altra scelta, ma per usare un puntatore. MA: l'uso afferma in tutta la vostra funzione membro di rilevare rapidamente sbagliato stato puntatore
  • Nei casi in cui si desidera che il ciclo di vita dell'oggetto di essere dipendente dalla vita di un oggetto esterno, ed è anche necessario che il tipo di essere copiabile, quindi utilizzare i membri di puntatore ma argomento di riferimento nel costruttore questo modo si è indicando sulla costruzione che la durata di questo oggetto dipende la vita del argomento, ma i puntatori usare l'esecuzione di essere ancora copiabile. Fino a quando questi membri sono cambiati solo da copiare, e il tipo di non avere un costruttore di default, il tipo dovrebbe adempiere a entrambi gli obiettivi.

Oggetti raramente dovrebbero consentire di assegnazione e altre cose come confronto. Se si considera un certo modello di business con oggetti come 'Dipartimento', 'dipendente', 'direttore', è difficile immaginare un caso in cui un dipendente verrà assegnata ad altri.

Quindi, per oggetti di business è molto buono per descrivere uno-a-uno e uno-a-molti come riferimenti e non puntatori.

E probabilmente è OK per descrivere una o zero rapporto come un puntatore.

Quindi no 'non possiamo assegnare' quindi fattore.
Un sacco di programmatori solo abituarsi con puntatori e questo è il motivo per cui essi troveranno alcun argomento per evitare l'uso di riferimento.

Avere un puntatore come membro costringerà voi o membro del team per controllare di nuovo e di nuovo il puntatore prima dell'uso, con commento "just in case". Se un puntatore può essere zero, allora probabilmente puntatore viene utilizzato come una specie di bandiera, che è male, come ogni oggetto deve svolgere il proprio ruolo.

In alcuni casi importanti, non è semplicemente necessario cedibilità. Si tratta spesso di involucri leggeri algoritmo che facilitano il calcolo senza lasciare il campo di applicazione. Tali oggetti sono i primi candidati per i membri di riferimento dal momento che si può essere sicuri che hanno sempre in possesso di un valida di riferimento e non devono essere copiati.

In questi casi, assicurarsi di fare l'operatore di assegnazione (e spesso anche il costruttore di copia) non utilizzabile (ereditando da boost::noncopyable o dichiarandoli privato).

Tuttavia, come pts utente già commentato, lo stesso non vale per la maggior parte degli altri oggetti. Qui, utilizzando i membri di riferimento può essere un problema enorme e deve essere generalmente evitato.

Per quanto tutti sembrano essere distribuendo le regole generali, ti offro due:

  • Mai, mai usare uso riferimenti come membri della classe. Non ho mai fatto in mio codice (tranne che per dimostrare a me stesso che avevo ragione a questa regola) e non riesco a immaginare un caso in cui lo farei. La semantica è troppo confuso, e non è davvero quello che i riferimenti sono stati progettati per.

  • Sempre, sempre, utilizzare i riferimenti quando il passaggio di parametri alle funzioni, tranne che per i tipi di base, o quando l'algoritmo richiede una copia.

Queste regole sono semplici, e mi hanno resistito al posto buono. Lascio fare le regole sull'utilizzo di puntatori intelligenti (ma per favore, non auto_ptr) come membri della classe per gli altri.

Sì per:? E 'vero dire che un oggetto contenente un riferimento non dovrebbe essere assegnabili, dal momento che un riferimento non deve essere cambiato una volta inizializzato

Le mie regole pratiche per i membri di dati:

  • non usare mai un riferimento, perché impedisce l'assegnazione
  • Se la classe è responsabile della cancellazione, scoped_ptr l'uso di spinta (che è più sicuro di un auto_ptr)
  • In caso contrario, utilizzare un puntatore o puntatore const
  

Sono in genere utilizzare solo un puntatore a dati utente quando il puntatore potrebbe essere nullo o potrebbe cambiare. Ci sono altre ragioni per preferire puntatori oltre riferimenti per i membri di dati?

Sì. Leggibilità del codice. Un puntatore rende più evidente che l'utente è un riferimento (ironicamente :)), e non un oggetto contenuto, perché quando lo si utilizza è necessario de-reference di esso. So che alcune persone pensano che è vecchio stile, ma io continuo a pensare che semplicemente evitare la confusione e gli errori.

Vi consiglio contro i membri di dati di riferimento becasue si sa mai chi sta per derivare dalla classe e che cosa si potrebbe desiderare di fare. Potrebbero non vuole fare uso dell'oggetto di riferimento, ma essendo un punto di riferimento che li hanno costretti a fornire un oggetto valido. Ho fatto questo per me stesso abbastanza per smettere di usare componenti di dati di riferimento.

Se ho capito correttamente alla domanda ...

di riferimento come parametro di funzione invece di puntatore: Come lei ha sottolineato, un puntatore non mettere in chiaro chi possiede la pulizia / inizializzazione del puntatore. Preferisco un punto condiviso quando si desidera un puntatore, è una parte di C ++ 11, e un weak_ptr quando la validità dei dati non è garantita attraverso il ciclo di vita della classe accettare la punta ai dati .; anche una parte di C ++ 11. Utilizzare un riferimento come parametro funzione garantisce che il riferimento non è nullo. Dovete sovvertire le caratteristiche del linguaggio per aggirare questo, e noi non si preoccupano di codificatori mina vagante.

Riferimento un una variabile membro: Come come sopra per quanto riguarda la validità dei dati. Questo garantisce la punta ai dati, quindi si fa riferimento, è valido.

Moving responsabilità di validità variabile da un punto precedente nel codice pulisce non solo il codice più tardi (la classe A nel tuo esempio), ma rende anche chiaro alla persona che utilizza.

Nel tuo esempio, che è un po 'di confusione (mi piacerebbe molto provare a trovare un'implementazione più chiara), l'A usato da B è garantito per tutta la durata della B, dato che B è un membro di A, quindi un riferimento rafforza questo ed è (forse) più chiaro.

E solo nel caso (che è un basso cappuccio probabile in quanto non avrebbe alcun senso nel vostro contesto codici), un'altra alternativa, di utilizzare un non fa riferimento, non puntatore Un parametro, sarebbe esemplare A, e rendere il paradigma inutili -. io davvero non credo che dire che questo come alternativa

Inoltre, questo garantisce anche che non sono in grado di modificare i dati a cui fa riferimento, in cui un puntatore può essere modificato. Un puntatore const avrebbe funzionato, solo se il riferimento / puntatore ai dati non era mutevole.

I puntatori sono utili se il parametro A per B non è stato garantito da impostare, o potrebbe essere riassegnato. E a volte un debole puntatore è solo troppo prolisso per l'implementazione, e un buon numero di persone che o non sanno cosa sia un weak_ptr è, o semplicemente non amano.

lacerare questa risposta, per favore:)

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top