2011-11-19 9 views
9

Qual è un buon modo per condividere un'istanza di un oggetto tra più classi in una gerarchia di classi? Ho la seguente situazione:Qual è un buon modo per condividere un oggetto tra le classi?

class texture_manager; 

class world { 
    ... 
    std::vector<object> objects_; 
    skybox skybox_; 
} 

Io attualmente implementato texture_manager come Singleton, ed i clienti chiamare il suo metodo di istanze da qualsiasi parte del codice. texture_manager deve essere utilizzato da object s nel vettore objects_, da skybox_ e possibilmente da altre classi che possono o meno far parte della classe world. Come sto cercando di limitare l'uso di singleton nel mio codice, mi consigliate qualche alternativa a questo approccio? Una soluzione che mi viene in mente sarebbe quella di passare un riferimento a texture_manager come argomento ai costruttori di tutte le classi che hanno bisogno di accedervi. Grazie.

+1

Perché non dichiarare solo un'istanza globale di texture_manager? I Globali non sono malvagi se vengono gestiti correttamente. E non sono né meno né più pericolosi in un ambiente filettato rispetto a qualsiasi altra istanza passata a più client ... – Mordachai

risposta

10

La risposta generale a questa domanda è l'uso di ::std::shared_ptr. O se non lo hai, ::std::tr1::shared_ptr, o se non lo hai, ::boost::shared_ptr.

Nel vostro caso particolare, mi sento di raccomandare uno dei pochi approcci diversi:

  1. Una possibilità è, naturalmente, l'approccio shared_ptr. In pratica passate il vostro puntatore a chiunque abbia bisogno dell'oggetto, e viene automaticamente distrutto quando nessuno di essi ne ha più bisogno. Anche se il tuo gestore delle trame finirà con i puntatori agli oggetti che lo puntano, stai creando un ciclo di riferimento, che dovrà essere gestito con molta attenzione.

  2. Un'altra possibilità è solo dichiararla come variabile locale in main e passarla come puntatore o riferimento a tutti coloro che ne hanno bisogno. Non andrà via finché il tuo programma non sarà finito in quel modo, e non dovresti preoccuparti di gestire la vita. In questo caso, un puntatore o riferimento nullo va bene.

  3. Una terza possibilità è uno degli usi vagamente accettabili di qualcosa di simile a un singleton. E questo merita una spiegazione dettagliata.

È un singleton il cui unico lavoro è fornire indicazioni utili alle cose. Una caratteristica chiave che ha è la capacità di dirgli a quale oggetto dare un puntatore. È un po 'come una fabbrica globale configurabile.

Ciò consente di evitare gli enormi problemi di test creati con un singleton in generale. Dillo solo a distribuire un puntatore a un oggetto stub quando arriva il momento di testare le cose.

Consente inoltre di uscire dal problema del controllo di accesso/sicurezza (sì, creano anche problemi di sicurezza) che un singleton rappresenta per lo stesso motivo. Puoi dire temporaneamente di passare un puntatore a un oggetto che non consente l'accesso a cose a cui la sezione di codice che stai per eseguire non ha bisogno di accedere. Questa idea è generalmente indicata come il principio di minima autorità.

Il motivo principale per utilizzare questo è che consente di risparmiare il problema di capire chi ha bisogno del puntatore e consegnarlo a loro. Questo è anche il motivo principale per non usarlo, pensando che è un bene per te. Introduci anche la possibilità che due cose che si aspettano di ottenere lo stesso puntatore a un gestore di texture ottengano effettivamente dei puntatori a un gestore di texture diverso a causa di un flusso di controllo che non hai previsto, che è fondamentalmente il risultato del pensiero trascurato che ti ha causato per usare il Singleton in primo luogo.Infine, Singletons è così terribile, che anche questo uso più gentile di loro mi fa prudere.


Personalmente, nel tuo caso, mi sento di raccomandare l'approccio # 2, solo la creazione in pila in main e passando in un puntatore a ovunque sia necessario. Ti farà riflettere più attentamente sulla struttura del tuo programma, e questo tipo di oggetto dovrebbe probabilmente vivere per tutta la vita del tuo programma comunque.

+2

Penso che l'uso di una sorta di puntatore condiviso qui sia solo un modo per orientarsi in modo approssimativo (ma importante) discussione su chi possiede effettivamente l'oggetto 'texture_manager'. Dovrebbe davvero essere distrutto non appena nessuno ha più un riferimento ad esso? –

+1

Ci ho pensato, tuttavia passare una shared_ptr in basso alla gerarchia delle classi sembra complicato, e spero di trovare una soluzione alternativa. O non è questo quello che avevi in ​​mente? –

+0

@FrerichRaabe: Sì, l'ho appena inserito come primo taglio del "consiglio standard". È quello che mi ha immediatamente fatto pensare alla domanda. Ma l'ho analizzato un po 'più in profondità e ho aggiornato la mia risposta. – Omnifarious