Ich möchte eine Struktur definieren, z.B. type
, sodass sizeof(type)
nicht kleiner als ein Wert ist.
Motivation:
Ich habe einen Vektor std::vector<type>
und ich werde einige Elemente daraus entfernen. Außerdem habe ich die Indizes einiger Elemente an anderen Stellen gespeichert, daher möchte ich sie einfach als nicht verwendet markieren und sie in Zukunft wiederverwenden. Dies führt mich dazu, die nächste verfügbare Position als eine Liste in gelöschten Positionen zu speichern. Daher sollte sizeof(type)
nicht weniger als sizeof(size_t)
und type
korrekt ausgerichtet sein.
Mögliche Lösungen:
boost::variant<type, size_t>
Das hat aus meiner Sicht zwei Probleme. Wenn ich use boost::get<type>
, wird die Leistung deutlich sinken. Wenn ich boost::apply_visitor
verwende, wäre die Syntax komisch und die Leistung würde auch entsprechend meinem Profil abnehmen.
union{type t; size_t s;}
Das funktioniert natürlich bis auf zwei Defizite. Erstens wäre die Syntax für den Verweis auf type
unordentlicher. Zweitens muss ich Konstruktor, Kopierkonstruktor usw. für diese Vereinigung definieren.
Erweitern Sie type
by char[sizeof(size_t) - sizeof(type)]
Das entspricht fast meinen Anforderungen. Dies birgt jedoch das Risiko von Arrays mit einer Länge von Null, die vom C ++ - Standard und möglicherweise falscher Ausrichtung nicht unterstützt werden.
Da ich type
nicht oft als size_t
verwenden werde, möchte ich nur sicherstellen, dass ich reinterpret_cast<size_t>
bei Bedarf verwenden kann.
Ergänzungen
Nach dem Lesen der Kommentare denke ich, dass die beste Lösung für mein Problem boost::variant
sein sollte. Aber ich frage mich immer noch, ob es einen Weg gibt, die Vorteile von Lösung 2 und 3 zu kombinieren, d.h.
a. Ich kann auf Mitglieder von type
ohne Änderungen zugreifen.
b. Holen Sie sich die Garantie, dass reinterpret_cast<size_t>
funktioniert.
Sie können die Bedenken bezüglich Lösung 3 durch etwas wie:
abschwächen %Vor%Dieser Code:
pad
vollständig aus type
layout heraus optimiert werden kann wenn sizeof(data) >= sizeof(size_t)
Obwohl dies ein interessantes Problem ist, sieht das Design selbst fragwürdig aus.
Beim Einfügen eines neuen Elements werden Elemente, die nicht verwendet wurden, zuerst berücksichtigt, bevor der Vektor vergrößert wird. Dies bedeutet, dass die relative Reihenfolge der Elemente nicht vorhersehbar ist. Wenn das akzeptabel ist, hätten Sie einfach einen Vektor von (intelligenten) Zeigern verwenden können.
Normalerweise ist ein Vektor ineffizient, wenn Objekte aus der Mitte entfernt werden. Da die Reihenfolge keine Rolle spielt, ist es möglich, das zu entfernende Element durch das letzte Element zu ersetzen und das letzte Element zu öffnen.
Alle Elemente haben die gleiche Größe; ihre Zuordnung mit einem Pool könnte schneller sein als die Verwendung des System-Allokators.
Ein Pool reserviert grundsätzlich Speicher in großen Blöcken und teilt auf Anfrage kleinere Blöcke aus. Ein Pool speichert die freie Liste normalerweise in noch nicht zugeordneten Blöcken, um den verfügbaren Speicher zu verfolgen (dieselbe Idee, die in der Frage beschrieben wird). Es gibt einige gute Implementierungen, die leicht verfügbar sind (von Boost und anderen Quellen).
In Bezug auf das ursprüngliche Design ist es umständlich, Elemente im Vektor aufzuzählen, da reale Elemente mit "Löchern" gemischt sind, die Logik wird mit zusätzlichen Überprüfungen verschleiert.
Wahrscheinlich gibt es einige verkaufte Argumente hinter dem ursprünglichen Design; leider @ user1535111 erzählt nicht die Details.