2009-06-24 9 views
14

Quando si lavora con puntatori e riferimenti in C++, a volte è difficile vedere se il puntatore ha la proprietà sui dati di riferimento o se è solo un riferimento temporale. Per esempio:Come rendere esplicita la proprietà dei dati in C++

Instance* i = new Instance(); 
Instance* j = i; 

Come può essere chiarito quale dei 2 puntatori ha la proprietà sopra l'istanza? In altre parole, come chiarire su quale puntatore cancellare deve essere chiamato?

Nota: Nell'esempio precedente questo non è difficile da vedere, in quanto è un codice molto breve. Tuttavia, quando il puntatore viene duplicato e passato molto, questo può diventare non chiaro.

+3

la tua domanda non ha senso. nessun riferimento ha 'proprietà'. Sono entrambi, riferimenti ugualmente validi –

+0

Questo è esattamente il mio problema, e mi chiedo come sia meglio documentare quale puntatore ha la responsabilità di eliminare l'istanza. Mi piacerebbe un linguaggio per questo, anche se non ho idea di come questo possa essere fatto. –

+0

+1 Perché stai facendo downvoting a questa domanda? – ralphtheninja

risposta

7

Non è possibile determinare il proprietario, poiché non esiste un meccanismo incorporato per sapere quale puntatore possiede la memoria a cui punta il puntatore.

Se si è veramente preoccupati di questo, è sempre possibile introdurre la propria convenzione di denominazione, ad es. attraverso alcuni pre/post-fix ai nomi delle variabili. In altre parole, è la progettazione del codice che può darti queste informazioni. Dal momento che tu (e i tuoi colleghi) stai scrivendo il codice puoi sempre assicurarti che questo disegno venga applicato durante l'implementazione. Questo ovviamente significa che tutti devono seguire queste "regole".

Questo è uno dei motivi per cui una convenzione di codifica comune è così importante. In questo modo puoi leggere il tuo codice e quello degli altri e comprenderlo.

7

In primo luogo, sembra inutilmente confondente utilizzare un riferimento per fare riferimento a dati che devono essere eliminati. Usa invece un puntatore.

In secondo luogo, se si desidera indicare la proprietà di un oggetto, utilizzare una classe wrapper che gestisce la proprietà. C'è lo auto_ptr appositamente per questo scopo, sebbene abbia delle imperfezioni. (Questi dovrebbero essere indirizzati da unique_ptr nella prossima versione della lingua, anche se questo non ti aiuta ora).

In terzo luogo, nei casi più semplici (il più spesso possibile), non utilizzare direttamente l'heap. Basta dichiarare un oggetto locale, ad es.

std::vector<int> v; 

Questo non si ferma si trasferimento di proprietà quando è necessario (usare swap).

+0

Questo è solo un esempio. Quando si utilizza il polimorfismo, è necessario. –

+1

Uso sempre il polimorfismo in C++. Non l'ho mai trovato necessario. –

+4

Non è necessario utilizzare un riferimento per il polimorfismo. Un puntatore funziona bene. Se hai un riferimento a un oggetto, è come dire "Qualunque cosa tu faccia, non cancellarla!" Con un puntatore, è più aperto all'eliminazione (anche se richiede ancora una comprensione del design/proprietà). –

3

È possibile utilizzare qualcosa come shared_ptr<> per condividere in modo esplicito la proprietà. Se si vuole mantenere una chiara proprietario singolo con altri puntatori non proprietario che si riferiscono allo stesso oggetto, si potrebbe usare qualcosa come boost::scoped_ptr<> per il puntatore possedere e hanno un typedef per i puntatori non proprietario:

typedef Instance* UnownedInstance_ptr; // or some better name 

Questo sarebbe almeno l'intento del documento. Non conosco un modo per non avere un tipo di puntatore intelligente che impedisce la possibilità di eliminare il puntatore contenuto e impedire di copiare il puntatore in un altro puntatore intelligente che ne assume la proprietà (poiché la fonte non ha proprietà da regalare), ma quella potrebbe essere una classe interessante per rappresentare quella politica.

3

Per me vorrei andare con la notazione ungherese!

Joel ti dice il resto :: Making Wrong Code Look Wrong

un esempio nel tuo caso ::

Instance* Owener_i = new Instance(); 
Instance* Observer_j = i; 
. 
. 
. 
. 
. 
delete Observer_j; // Wrong! not an Owner. 
2

Mentre gli altri indicato - utilizzare una convenzione. Uso i puntatori grezzi per le variabili non proprietarie e il proprietario è solitamente racchiuso in una sorta di puntatore intelligente (come boost :: scoped_ptr) o addirittura non un puntatore ma un oggetto creato nello stack.

Problemi correlati