2009-06-24 11 views
14

Wenn Sie mit Zeigern und Verweisen in C++ arbeiten, ist es manchmal schwierig zu erkennen, ob der Zeiger über die referenzierten Daten verfügt oder nur eine temporäre Referenz ist. Zum Beispiel:So machen Sie Datenbesitz explizit in C++

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

Wie kann es, welche der zwei Zeiger hat das Eigentum über die Instanz deutlich gemacht werden? Mit anderen Worten, wie klar machen, auf welchen Zeiger löschen muss aufgerufen werden?

Hinweis: Im obigen Beispiel ist dies nicht schwer zu sehen, da es sich um ein sehr kurzes Stück Code handelt. Wenn der Zeiger jedoch dupliziert und viel herumgereicht wird, kann dies unklar werden.

+3

Ihre Frage ergibt keinen Sinn. Keine der Referenzen hat "Eigentum". Sie sind beide gleichermaßen gültige Referenzen –

+0

Das ist genau mein Problem, und ich frage mich, wie es am besten zu dokumentieren, welcher Zeiger die Verantwortung hat, die Instanz zu löschen. Ich hätte gerne eine Sprachfunktion dafür, obwohl ich keine Ahnung habe, wie das gemacht werden könnte. –

+0

+1 Warum redest du diese Frage? – ralphtheninja

Antwort

7

Sie können den Besitzer nicht bestimmen, da es keinen integrierten Mechanismus gibt, um zu wissen, welcher Zeiger den Speicher besitzt, auf den der Zeiger zeigt.

Wenn Sie wirklich besorgt sind, könnten Sie immer Ihre eigene Namenskonvention einführen, z. durch einige Pre/Post-Fix zu Ihren Variablennamen. Mit anderen Worten, es ist Ihr Code-Design, das Ihnen diese Informationen geben kann. Da Sie (und Ihre Mitarbeiter) den Code schreiben, können Sie immer sicherstellen, dass dieses Design während der Implementierung durchgesetzt wird. Das bedeutet natürlich, dass jeder diese "Regeln" befolgen muss.

Dies ist ein Grund, warum eine gemeinsame Kodierungskonvention so wichtig ist. So können Sie Ihren eigenen und anderen Code lesen und verstehen.

7

Erstens scheint es unnötigerweise verwirrend, eine Referenz zu verwenden, um auf Daten zu verweisen, die gelöscht werden müssen. Verwenden Sie stattdessen einen Zeiger.

Wenn Sie zweitens den Besitz eines Objekts angeben möchten, verwenden Sie eine Wrapper-Klasse, die den Besitz verwaltet. Es gibt auto_ptr speziell für diesen Zweck, obwohl es Mängel aufweist. (Diese sollten von unique_ptr in der nächsten Version der Sprache angesprochen werden, obwohl das Ihnen jetzt nicht hilft).

Drittens, verwenden Sie in den einfachsten Fällen (so oft wie möglich) den Heap nicht direkt. Erklären Sie einfach ein lokales Objekt, z.B.

std::vector<int> v; 

Dies gilt nicht stoppen Sie den Besitz Übertragung, wenn Sie müssen (verwenden swap).

+0

Dies ist nur ein Beispiel. Wenn Polymorphie verwendet wird, ist es notwendig. –

+1

Ich verwende Polymorphie die ganze Zeit in C++. Ich habe es nie nötig gefunden. –

+4

Es ist nicht notwendig, eine Referenz für Polymorphie zu verwenden. Ein Zeiger funktioniert gut. Wenn Sie einen Verweis auf ein Objekt haben, ist es so, als würde man sagen: "Was auch immer du tust, lösche das nicht!" Mit einem Zeiger ist es offener zu löschen (obwohl immer noch ein Verständnis für das Design/Eigentum benötigt). –

3

Sie können etwas wie shared_ptr<> verwenden, um das Eigentumsrecht explizit zu teilen. Wenn Sie einen klaren Einzel Besitzer mit anderem Nicht-Besitzer Zeiger auf das gleiche Objekt erhalten mögen, können Sie so etwas wie boost::scoped_ptr<> für den Besitz Zeiger und eine typedef für nicht-besitzende Zeiger verwenden:

typedef Instance* UnownedInstance_ptr; // or some better name 

Dies würde zumindest Absichtserklärung. Ich weiß nicht, dass ich einen intelligenten Zeigertyp habe, der verhindert, dass der enthaltene Zeiger gelöscht wird, und verhindert, dass der Zeiger in einen anderen intelligenten Zeiger kopiert wird, der den Besitz übernimmt (da die Quelle keine besitzt) Besitz zu verschenken), aber das könnte eine interessante Klasse sein, um diese Politik zu repräsentieren.

3

Für mich würde ich mit der ungarischen Notation gehen!

Joel sagt Ihnen, den Rest :: Making Wrong Code Look Wrong

ein Beispiel, in Ihrem Fall ::

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

Wie die anderen angegeben - eine Konvention verwenden. Ich benutze rohe Zeiger für nicht besitzende Variablen, und der Besitzer wird normalerweise in irgendeine Art von Smart-Pointer (wie boost :: scoped_ptr) oder gar nicht in einen Zeiger, sondern in ein Objekt, das auf dem Stapel erstellt wurde, eingewickelt.

Verwandte Themen