Piktogramm schrieb:
Jain, es kommt drauf an, wie groß im Mittel die Strings aus L1 sind. In deinem Beispiel sind in L1 eigentlich nur Chars, im Indexvektor aber uInt32. Entsprechend ist der volle Index in deinem Beispiel immer größer als die Nutzdaten. Das Verhältnis verschiebt sich halt.
Die Größe eines std::string ist immer (!) dieselbe (also eine Konstante) und für eine gegebene Implementierung per
sizeof(std::string) bereits zur Kompilierzeit ermittelbar. Damit ist auch das memory, dass ein
std::vector<std::string> mindestens benötigt, für eine gegebene Anzahl an Elementen darin ebenfalls fix vorgegeben.
Typische std::string-Implementierungen bestehen z.B. aus einem pointer zum dazugehörigen Character-Array und einen unsigned int Wert für die Anzahl an characters in diesem Array, also schematisch ca. so (mit char als Charracter-Typ):
class string {
unsigned int size;
char * p;
}
Auf einem 32-bit System ist die Größe damit typischerweise 8 Bytes, und auf einem 64-bit System 16 Bytes.
Und das ist auf jeden Fall größer als ein
uint32_t, weswegen der Index-Vector also weniger Speicherplatz benötigt als der String-Vector.
(Das von
p referenzierte Character-Array nimmt zur Laufzeit natürlich weiteren Speicherplatz ein, ist aber nicht Teil der String-Klasse selbst, und beeinflusst daher folglich weder
sizeof(std::string) noch den Memory-Bedarf des String-Vectors).
Exkurs:
Obige Implementierung entspricht eher der Anfangszeit von std::string Implementierungen. Später wurde dann die geniale Idee der small-string Optimization entwickelt: Wenn ein String-Wert nur aus wenigen Zeichen besteht (was in der Praxis häufig vorkommt), kann man diese Character-Werte DIREKT in den von
size und
p belegten Bytes speichern und sich damit das dynamische Character-Array komplett ersparen. Das spart dann nicht nur bei der string-Erstellung oder beim Kopieren dieses Strings die jeweilige memory-allocation, sondern bei jedem Zugriff auf den String auch noch den Indirektions-Weg zu diesem Character-Array. Enorme Ersparnis!
Eine Umsetzung dieser small-string Optimization könnte z.B. so aussehen:
Ein bit in
size speichert ob die Character-Werte direkt lokal im std::string Objekt oder in einem externen Character-Array liegen. Falls ersteres der Fall ist, liegen diese Character-Werte dann direkt in den restlichen von
size und
p belegten Bytes. Auf einer typischen 64-bit Plattform kann man also einen String-Wert bestehend aus maximal 15 Character-Werten direkt im string-Objekt selbst speichern (das erste Byte von
size enthält dabei sowohl das obige Bit-Flag wie auch dann in den restlichen Bits dieses Bytes gespeichert die Anzahl der Character-Werte).
Ob diese Variation genutzt wird, und falls ja, wie genau diese umgesetzt ist, liegt natürlich vollkommen im Ermessen der Implementierung.
Dass der OP nicht hard-codiert
uint32_t als Typ für die Indices nehmen sollte, sondern besser
typename std::vector<T>::size_type (was typischerweise
std::size_t ist, und somit auf 64-bit Plattformen typischerweise auf einen 64-bit Integer Typ hinausläuft) ist wiederum eine ganz andere Sache (dann benötigt der Index-Vector auch entsprechend mehr memory), und wird dem OP hoffentlich auffallen falls sein vector je mal mehr als 2^32 Elemente enthalten sollte und sich seine Funktion zum Ziehen daraus dann etwas unerwartet verhält ...