Was ist der beste Weg, ein assoziatives Array mit beliebigen Werttypen für jeden Schlüssel in C ++ zu erstellen?
Gegenwärtig plane ich, eine "Wert" -Klasse mit Mitgliedsvariablen der Typen zu erstellen, die ich erwarten werde. Zum Beispiel:
%Vor%Ein Nachteil dabei ist, dass Sie den Typ beim Zugriff auf den "Wert" kennen müssen. d.h.:
%Vor%Je mehr Typen in Value eingefügt werden, desto aufgeblähter wird das Array.
Irgendwelche besseren Vorschläge?
Ihr Vorgehen war im Grunde in die richtige Richtung. Sie müssen den Typ kennen, in den Sie eingefügt werden. Sie können boost::any
verwenden und Sie können so gut wie alles in die Karte einfügen, solange Sie wissen, in was Sie hineingelegt haben:
Einige Antworten empfahlen die Verwendung von boost::variant
, um dieses Problem zu lösen. Aber Sie können keine willkürlichen typisierten Werte in der Karte speichern (wie Sie es wollten). Sie müssen die Menge der möglichen Typen vorher kennen. In Anbetracht dessen können Sie das obige leichter tun:
Das funktioniert, weil boost::variant
überlädt operator<<
für diesen Zweck. Es ist wichtig zu verstehen, dass Sie, wenn Sie das aktuell in der Variante enthaltene speichern möchten, den Typ immer noch wissen müssen, wie im Fall boost::any
:
Die Reihenfolge der Zuweisungen zu einer Variante ist eine Laufzeiteigenschaft des Steuerungsflusses Ihres Codes, aber der Typ einer beliebigen Variablen wird zum Zeitpunkt der Kompilierung festgelegt. Wenn Sie also den Wert aus der Variante herausholen wollen, müssen Sie dessen Typ kennen. Eine Alternative ist die Verwendung von Visitationen, wie in der Variantendokumentation beschrieben. Es funktioniert, weil die Variante einen Code speichert, der angibt, welcher Typ ihm zuletzt zugewiesen wurde. Darauf basierend entscheidet zur Laufzeit welche Überladung der Besucher verwendet. boost::variant
ist ziemlich groß und nicht vollständig standardkompatibel, während boost::any
standardkonform ist, aber dynamischen Speicher auch für kleine Typen verwendet (daher ist es langsamer. Variante kann den Stapel für kleine Typen verwenden). Sie müssen also abwägen, was Sie verwenden.
Wenn Sie tatsächlich Objekte hineinlegen wollen, die sich nur dadurch unterscheiden, wie sie etwas tun, dann ist Polymorphie ein besserer Weg. Sie können eine Basisklasse haben, von der Sie abgeleitet sind:
%Vor%Was würde dieses Klassenlayout grundsätzlich erfordern:
%Vor% Der boost::shared_ptr
ist ein so genannter Smart Pointer. Es löscht Ihre Objekte automatisch, wenn Sie sie aus Ihrer Karte entfernen und nichts mehr auf sie verweist. Theoretisch hätten Sie auch mit einem einfachen Zeiger arbeiten können, aber die Verwendung eines intelligenten Zeigers wird die Sicherheit erheblich erhöhen. Lies das Handbuch shared_ptr, mit dem ich verlinkt bin.
Können Sie eine Union mit std :: map verwenden?
Boost :: variant bietet typlose Variablen.
Alternativ können Sie alle Datenelemente für "Wert" als privat festlegen und Zugriffsberechtigungen bereitstellen, die einen Fehler (oder "throw") zurückgeben, wenn dieser Wert nicht festgelegt ist.
Eine direkte Optimierung wäre die Verwendung von union
, da Sie immer nur einen der Werte als Schlüssel haben.
Eine vollständigere Lösung würde einige Laufzeittypinformationen in eine Schnittstelle einkapseln. In erster Linie "Welcher Typ ist das?" und "Wie vergleiche ich Werte für Gleichheit?" Verwenden Sie dann Implementierungen von diesem als Schlüssel.