Sono in una situazione in cui ho un ciclo di dipendenza circolare tra le definizioni di due classi, dove (per quanto posso dire) entrambe le classi hanno bisogno che l'altro tipo sia un tipo completo per definirle correttamente.Praticamente sicuro di assumere sizeof (std :: unordered_map <std :: string, T>) è lo stesso per tutti i T?
In termini semplificati, quello che mi serve versione semplificata di ciò che accade:
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_;
};
La situazione è in realtà più complicata di quanto sopra, poiché Node
è in realtà sarà di tipo variante (simile a boost::variant
) che utilizza il posizionamento nuovo per costruire esplicitamente uno di più tipi di oggetti in un buffer preallocato (e con allineamento corretto, che sto ignorando in questa semplificazione): il buffer non è quindi esattamente sizeof(Map)
ma piuttosto una costante calcolata che dipende da sizeof(Map)
.
Il problema, ovviamente, è che sizeof(Map)
non è disponibile quando Map
viene inoltrato solo in avanti. Inoltre, se cambio l'ordine delle dichiarazioni da inoltrare prima dichiarare Node
, la compilazione di Map
non riesce, poiché std::unordered_map<std::string, Node>
non può essere istanziato quando Node
è un tipo incompleto, almeno con il mio GCC 4.8.2 su Ubuntu. (Lo so che dipende dalla libstdC++ versione più rispetto alla versione GCC, ma non so come trovare facilmente quello ...)
In alternativa, sto considerando la seguente soluzione:
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");
Questo fondamentalmente si basa sul presupposto che std::unordered_map<std::string, T>
abbia la stessa dimensione per tutti i T, il che sembra essere valido per i miei test con GCC.
La mia domanda è dunque triplice:
C'è qualcosa nello standard C++ che richiede che questa ipotesi di tenere vero? (Sto assumendo di no, ma se c'è sarei piacevolmente sorpreso ...)
In caso contrario, è praticamente lecito ritenere che vale per tutte le implementazioni ragionevoli in ogni caso, e che l'affermazione statica nella mia versione rivista non sparerà mai?
Infine, c'è una soluzione migliore a questo problema a cui non ho pensato? Sono sicuro che è possibile che ci sia qualcosa di ovvio che posso fare, invece, che non ho pensato, ma purtroppo non posso pensare a niente ...
I commenti non sono per discussioni estese; questa conversazione è stata [spostata in chat] (http://chat.stackoverflow.com/rooms/77815/discussion-on-question-by-trantorian-practicor-safe-to-assume-sizeofstdunor). – Taryn