Ich bin in einer Situation, wo ich eine zirkuläre Abhängigkeitsschleife zwischen den Definitionen von zwei Klassen habe, wo (so weit ich sagen kann) beide Klassen den anderen Typ benötigen, um ein vollständiger Typ zu sein, um sie richtig zu definieren.Praktisch sicher anzunehmen sizeof (std :: unordered_map <std :: string, T>) ist für alle T gleich?
Vereinfacht ausgedrückt, was ich vereinfachte Version müssen, was los ist:
struct Map;
struct Node {
// some interface...
private:
// this cannot be done because Map is an incomplete type
char buffer[sizeof(Map)];
// plus other stuff...
void* dummy;
};
struct Map {
// some interface...
private:
// this is Map's only member
std::unordered_map<std::string, Node> map_;
};
Die Situation ist tatsächlich komplizierter als die oben, da Node
tatsächlich wird eine Variante Typ (ähnlich boost::variant
sein) das verwendet Placement neu, um explizit einen von mehreren Arten von Objekten in einem vorher zugeordneten (und mit richtiger Ausrichtung, die ich in dieser Vereinfachung ignoriere) Puffer zu konstruieren: der Puffer ist daher nicht genau sizeof(Map)
, sondern eher eine bestimmte Konstante, die abhängig ist sizeof(Map)
. Das Problem besteht offensichtlich darin, dass sizeof(Map)
nicht verfügbar ist, wenn Map
nur vorwärts deklariert ist. Außerdem, wenn ich die Reihenfolge der Deklarationen zu Forward deklarieren Node
zuerst, dann Kompilierung von Map
schlägt fehl, wie std::unordered_map<std::string, Node>
kann nicht instanziiert werden, wenn Node
ist ein unvollständiger Typ, zumindest mit meinem GCC 4.8.2 auf Ubuntu. (Ich weiß, es hängt von dem libstdC++ Version mehr als die GCC-Version, aber ich weiß nicht so leicht, wie das finden ...)
Als Alternative Ich betrachte die folgende Abhilfe:
struct Node {
// some interface...
private:
// doing this instead of depending on sizeof(Map)
char buffer[sizeof(std::unordered_map<std::string, void*>)];
// other stuff...
void* dummy;
};
struct Map {
// some interface...
private:
// this is Map's only member
std::unordered_map<std::string, Node> map_;
};
// and asserting this after the fact to make sure buffer is large enough
static_assert (sizeof(Map) <= sizeof(std::unordered_map<std::string, void*>),
"Map is unexpectedly too large");
Dies beruht im Wesentlichen auf der Annahme, dass std::unordered_map<std::string, T>
die gleiche Größe für alle T ist, die aus meinen Tests mit GCC wahr scheint. also dreifache
ist Meine Frage:
Gibt es etwas in der C++ Standard, der erfordert, dass diese Annahme wahr zu halten? (Ich gehe davon aus, nein, aber wenn es ist, würde ich angenehm überrascht sein ...)
Wenn nicht, ist es praktisch sicher davon ausgehen, es für alle vernünftigen Implementierungen gilt sowieso, und dass die statische Behauptung in meiner überarbeiteten Version wird nie feuern?
Schließlich gibt es eine bessere Problemumgehung für dieses Problem, an das ich nicht gedacht habe? Ich bin sicher, es ist möglich, es ist etwas offensichtlich, dass ich stattdessen tun kann, dass ich nicht gedacht haben, aber leider kann ich mich nichts ...
Kommentare sind nicht für längere Diskussion; Diese Konversation wurde [in den Chat verschoben] (http://chat.stackoverflow.com/rooms/77815/discussion-on-question-by-trantorian-practically-safe-to-assume-sizeofstdunor). – Taryn