Ich versuche eine einfache Klasse für die eindeutige ID-Konvertierung zu erstellen. Ich denke darüber nach, eine statische Methode hinzuzufügen:
%Vor% Jede Klasse würde dann durch das eindeutige int const *
identifiziert werden. Funktioniert das garantiert? Ist der zurückgegebene Zeiger wirklich eindeutig? Gibt es eine bessere, einfachere Lösung?
Ich habe auch über den Zeiger auf std::type_info
nachgedacht:
Ist das besser?
Bearbeiten:
Ich muss die ID nicht für die Serialisierung verwenden. Ich möchte nur eine kleine Menge von Basisklassen identifizieren und ich möchte, dass alle Unterklassen einer Klasse die gleiche ID haben
Wie ich zumindest bemerkt habe, optimiert MSVC 2008 oder 2010 die statische Variable, so dass die folgende Funktion GetId
dieselbe Adresse auch für verschiedene Klassen zurückgibt.
Daher kann die Adresse der nicht initialisierten konstanten statischen Variablen nicht zur Identifikation verwendet werden. Die einfachste Lösung ist das Entfernen von const
:
Eine andere Lösung zum Generieren von IDs, die scheinbar funktioniert, ist die Verwendung einer globalen Funktion als Zähler:
%Vor%Und dann definieren Sie die folgende Methode in den zu identifizierenden Klassen:
%Vor%Da die zu definierende Methode immer dieselbe ist, kann sie in eine Basisklasse eingefügt werden:
%Vor%Und dann verwenden Sie ein seltsam wiederkehrendes Muster:
%Vor% Ja, das wird funktionieren. Jedes static
local erhält zu dem Zeitpunkt, zu dem das Modul geladen wird, einen eindeutigen Speicherort, und es bleibt bestehen, bis das Modul entladen wird. Denken Sie daran, static
localhosts werden in statischem Speicher gespeichert, der während der Kompilierung verteilt wird, und sie bleiben bestehen, bis das Modul entladen wird, sodass sie unterschiedliche Speicherorte haben.
Die Adresse der statischen Variable ist garantiert eindeutig und in allen Übersetzungseinheiten gleich.
Es ist keine gute Idee, weil Sie Code zu jeder zu identifizierenden Klasse hinzufügen müssen.
Die Zeiger auf Typ-Info-Objekte sind nicht garantiert eindeutig, aber die Typ-Info-Objekte selbst werden garantiert als gleich für eine gegebene Klasse verglichen und als ungleich für verschiedene Klassen. Dies bedeutet, dass Sie kleine Wrapper-Objekte verwenden können, die Typ-Info-Zeiger enthalten, und die Vergleiche mit den Typ-Info-Objekten delegieren. C ++ 11 hat einen solchen Wrapper in der Standardbibliothek, und wenn Sie keinen Zugriff darauf haben, gibt es einen in Andrei Alexandrescus "Modern C ++ Design", und deshalb wahrscheinlich auch in der Loki-Bibliothek, in der es wahrscheinlich einen gibt Boost, und es gibt einen auf meinem Wordpress-Blog - es ist nicht so, als hättest du einen von Grund auf neu erfunden.
Wenn die IDs jedoch für die Serialisierung verwendet werden sollen, benötigen Sie IDs, die für Builds gültig sind. Und in diesem Fall brauchen Sie Strings oder UUIDs. Ich würde mit UUIDs gehen.
Um eine Klasse mit einer UUID zu verbinden, können Sie im Allgemeinen eine Typ-Traits-Klasse verwenden. Oder wenn Sie nur Windows-Programmierung durchführen, können Sie dafür die Spracherweiterungen von Visual C ++ verwenden. Ich denke aber ich bin nicht 100% sicher, dass diese Spracherweiterungen auch von g ++ (in Windows) implementiert werden.
Prost & amp; hth.
Die Adresse der statischen int
ist garantiert für jede eindeutig
Funktion (und das gleiche für jeden Aufruf der gleichen Funktion). So wie,
Es kann sehr gut als ID innerhalb einer einzigen Ausführung des Codes arbeiten.
Die Adresse könnte sich möglicherweise von einem Lauf zum nächsten ändern und wird dies auch tun
oft von einer Zusammenstellung zur nächsten wechseln (wenn Sie sich geändert haben
alles im Code), also ist es keine gute Lösung für eine externe ID.
(Sie sagen nicht, ob die ID außerhalb einer einzigen Ausführung gültig sein muss
oder nicht.)
Die Adresse der Ergebnisse eines typeid
ist nicht garantiert
Gleiches jedes Mal, wenn Sie die Funktion aufrufen (obwohl es wahrscheinlich sein wird).
Sie könnten es jedoch verwenden, um einen Zeiger zu initialisieren:
Im Vergleich zur Verwendung von int*
hat dies den Vorteil, zusätzliche Funktionen bereitzustellen
Informationen (z. B. zum Debuggen). Wie int*
, kann der Bezeichner sein
verschieden von einem Lauf zum nächsten; A::GetId()->name()
zeigt auf
die gleiche Zeichenfolge '%code%'
beendet (obwohl die Adresse möglicherweise erneut lautet)
anders) vorausgesetzt, Sie kompilieren mit dem gleichen Compiler. (Soweit ich
Kann sagen, der Standard garantiert das nicht, aber in der Praxis denke ich
Sie sind sicher.) Ändern Sie Compiler, und alle Wetten sind aus.
Die Lösung, die ich in der Vergangenheit verwendet habe, ist etwa:
%Vor%Dies bietet eine eindeutige Kennung, die leicht verglichen werden kann Ausführung des Codes und ein Zeichenfolgenwert, der als externe Kennung, und das ist über alle Compiler gewährleistet. Wir implementiert dies als ein Makro, das sowohl die statische Funktion definiert, und eine virtuelle Funktion, die sie zurückgab, z.B.:
%Vor%Dies führt zu einer sehr schnellen (aber begrenzten) RTTI und unterstützt externe Identifikatoren für Serialisierung und Persistenz.
Offensichtlich müssen Zeiger auf verschiedene Variablen unterschiedliche Werte haben. Achten Sie nur darauf, wenn Sie eine Unterklasse von A ableiten. Sie müssen entscheiden, was Ihre Richtlinie für die ID ist. Wenn Sie nichts tun, dann hätte die Unterklasse dieselbe ID.
Im Allgemeinen wollen Sie wirklich solche Hacky-Sachen vermeiden. Wenn ich das wirklich tun müsste, würde ich ein UUID-System verwenden (es gibt eine Boost-Bibliothek dafür, aber ich bin nicht sehr damit vertraut), oder ein Singleton, das eine Liste dieser Objekte zu welchem Zweck auch immer pflegte Sie brauchen.
Da Sie diese Methode allen Klassen hinzufügen müssen, die eine UID benötigen, können Sie dies auch tun.
%Vor%Der Vorteil davon ist, dass der Compiler eine Sprungtabelle verwenden kann, wenn Sie diese für RTTI zum Einschalten verwenden, was mit zwei Zeigern nicht möglich ist, weil die Sprungtabelle sehr spärlich wäre. p>
Der (kleinere) Nachteil besteht darin, dass Sie verfolgen müssen, welche Identifikatoren verwendet wurden.
Ein großer Nachteil der ersten von Ihnen vorgestellten Methode besteht darin, dass die gleichen Zahlen nicht zur Identifizierung von Objekten verwendet werden können, da die Methode virtual getUID () nicht in der Lage ist, die Adresse der Variablen im Rahmen einer anderen Funktion zu übernehmen.
Tags und Links c++