Angenommen, ich habe eine Menge gültiger Zeiger auf Instanzen einer Klasse A
. Kann ich sicher und portabel davon ausgehen, dass die Zeiger während der gesamten Lebensdauer des Objekts gleich bleiben? Mit anderen Worten, kann ich einen Zeiger auf ein Objekt als eindeutige Objekt-ID verwenden?
Sicher; Ich verstehe nicht warum.
Eine Speicheradresse ist so ziemlich die Definition der Objektidentität (einen Moment aus der Gleichung herausgenommen).
Nicht unbedingt - es hängt davon ab, wie Sie diese Instanzen zuweisen und was Sie dann mit ihnen tun. Angenommen, Sie erstellen ein Array von Objekten und weisen dieses Array dann neu zu. Es gibt jetzt keine Garantie, dass sich die Objekte noch immer am selben Ort befinden.
Sie können dies nur tun, wenn Sie sicher sind, dass kein Objekt mehr erstellt wird, sobald ein Objekt gelöscht wird. Das neue Objekt könnte an der gleichen Adresse eines zuvor gelöschten Objekts erstellt werden, und dies könnte ein Problem sein: Sie möchten nicht, dass zwei verschiedene Objekte dieselbe ID haben.
Es stimmt zwar, dass eine Speicheradresse ein Objekt eindeutig identifiziert. Es gibt zwei wichtige Vorbehalte:
Wenn ein Objekt gelöscht wird, kann die Adresse wiederverwendet werden (sehr wahrscheinlich für ein Objekt derselben Klasse).
Wenn Sie mit verschiedenen Prozessen arbeiten, können Adressen in beiden Prozessen identisch sein.
Solange das Objekt im Speicher bleibt und Sie immer auf die gleiche Instanz verweisen (z. B. wenn Sie es nicht nach Wert übergeben und dieses Objekt dann mit der ursprünglichen oder einer anderen zwischengespeicherten Kopie vergleichen), bleibt die Adresse immer gleich und der Zeiger ist eine sinnvolle ID. Dies ist natürlich richtig - wenn das Objekt im Speicher verschoben wird, würde der Zeiger nicht mehr funktionieren und der Standard garantiert, dass Zeiger auf verschiedene Objekte mit unterschiedlichen Werten verglichen werden. [Deshalb können Sie keine Objekte der Länge Null haben, daher hat das folgende Objekt im Speicher eine andere Adresse.]
Wenn das Objekt jedoch jemals über ein Netzwerk übertragen oder auf einem Datenträger gespeichert wird, funktioniert das offensichtlich nicht mehr. Sie müssen das Objekt Element für Element vergleichen oder ein eindeutiges Objekt einfügen ID-Wert (Primärschlüssel).
ETA: borrible ist korrekt, wenn Sie den Speicher, der die Objekte enthält, neu zuordnen, sind die Werte unterschiedlich, aber offensichtlich sind die Zeiger überhaupt nicht gültig, so dass Ihr Programm unterbrochen wird, wenn Sie erwarten, dass die Zeiger eindeutig sind oder nicht. (Umgekehrt, wenn Sie intelligente Punkte verwenden, die reacllocs verfolgen - im Wesentlichen, wie C # und .NET arbeiten - ist der Wert nicht notwendigerweise der gleiche, aber die Werte der Zeiger unterscheiden sich immer noch zwischen verschiedenen Instanzen des Objekts.) In der Tat ist das die Regel - solange die Zeiger gültig sind, sollten Sie sie vergleichen können, aber Sie können den Wert nicht zwischenspeichern und erwarten, dass er noch einige unbestimmte Zeit später funktioniert (falls Sie das Objekt zuerst zerstören) ), wenn du sicher bist, dass du es nicht tust, ist es in Ordnung, aber behalte es im Hinterkopf, oft wirst du die Objekte irgendwann serialisieren wollen, und dann ist es besser, sie von Anfang an so zu gestalten.
Eine Sorge (und es ist eine echte Sorge) ist Kuckuck Zeiger.
Angenommen, Sie speichern einen Zeigerwert A.
Geben Sie später diesen Zeiger frei, und weisen Sie später ein neues Objekt B zu.
Der Speicherzuordner kann den Speicherort auswählen, der für A verwendet wurde, um B zuzuordnen.
Code des Formulars: if (neuer_zeiger! = alter_zeiger) {...}
erkennt möglicherweise nicht, dass sich das Objekt geändert hat.
Bearbeiten:
Eine andere Möglichkeit, dies zu erreichen, besteht darin, dass Ihr Objekt immer am selben Ort ist, das Objekt an dieser Adresse jedoch nicht immer das Objekt ist, das Sie erwarten.
Wenn die Zeiger auf verschiedene Unterklassen nicht c-cast auf void * sind, dann ist es ja kein Problem, Zeiger zu vergleichen, um zu prüfen, ob es sich um das gleiche Objekt handelt.
Wenn die Adresse als void * - oder uint-Werte für ID-Zwecke gespeichert wird, gibt es einige weniger offensichtliche Probleme, die auftreten, wenn eine Klasse von mehreren Klassen erbt.
Betrachte Klasse C, die von Klasse A und Klasse B erbt. Wenn Klasse C über einen Zeiger der Klasse A referenziert wird, zeigt sie an, dass sie dasselbe Objekt über einen Zeiger der Klasse B referenziert.
%Vor%Wenn Sie jedoch ein C-Objekt von einem Zeiger der Klasse A auf einen void-Zeiger umwandeln, erhalten Sie möglicherweise die Adresse des Unterobjekts und nicht die Adresse des vollständigen Objekts. Die Typen werden dies im Normalfall verfolgen, und es ist nur eine Sorge, wenn ungültige Zeiger verwendet werden.
%Vor%Um die korrekte Adresse für das am weitesten abgeleitete und vollständige Objekt zu gewährleisten, verwenden Sie dynamic_cast (myObject). Beachten Sie jedoch, dass es eine polymorphe Klasse sein muss und RTTI aktiviert sein muss, damit dynamic_cast funktioniert.
Nur eine Sekunde zurück, jemand sagte, dass Polymorphismus beinhaltet multi Adressen für ein Objekt?
Ich bin mir ziemlich sicher, dass dies die virtuelle Funktionstabelle ist. Bevor Object1->func1()
als Typ bezeichnet wird, wird die Adresse von Object1
als Schlüssel für die vtable verwendet und eine Adresse für func1()
erhalten. Recht? Eine Neufassung machen, wie zurück zur Basisklasse wie:
macht das Schlüsselpaar address
+ type
anders und kann somit verschiedene Funktionszeiger zurückgeben.
So würde ich ohnehin die Runtime-Sachen schreiben. Weiß jedoch nicht über Mehrfachvererbung, was ein Greuel imo ist. Und ich verwende auch Objektadressen als ID
s. Ich kann wirklich keinen Fehler finden, kann jemand anderes?