
Martin Cott
Meine Frage ist einfach: sind std::vector
Elemente, die garantiert zusammenhängend sind? Mit anderen Worten, kann ich den Zeiger auf das erste Element von a verwenden std::vector
als C-Array?
Wenn ich mich recht erinnere, gab der C++-Standard keine solche Garantie. Allerdings ist die std::vector
Anforderungen waren derart, dass es praktisch unmöglich war, sie zu erfüllen, wenn die Elemente nicht zusammenhängend waren.
Kann das jemand klären?
Beispiel:
std::vector<int> values;
// ... fill up values
if( !values.empty() )
{
int *array = &values[0];
for( int i = 0; i < values.size(); ++i )
{
int v = array[i];
// do something with 'v'
}
}
Dies wurde im eigentlichen C++98-Standard übersehen, aber später als Teil eines TR hinzugefügt. Der kommende C++0x-Standard wird dies natürlich als Anforderung enthalten.
Aus n2798 (Entwurf von C++0x):
23.2.6 Klassenschablonenvektor [vector]
1 Ein Vektor ist ein Sequenzcontainer, der Iteratoren mit wahlfreiem Zugriff unterstützt. Darüber hinaus unterstützt es (amortisierte) konstante Einfüge- und Löschvorgänge am Ende; Einfügen und Löschen in der Mitte dauern linear. Die Speicherverwaltung erfolgt automatisch, es können jedoch Hinweise zur Effizienzsteigerung gegeben werden. Die Elemente eines Vektors werden zusammenhängend gespeichert, was bedeutet, dass wenn v ein Vektor ist, bei dem T ein anderer Typ als bool ist, er der Identität &v gehorcht[n] == &v[0] + n für alle 0 <= n < v.size().

Bill Lynch
Wie andere Antworten darauf hingewiesen haben, ist der Inhalt eines Vektors garantiert kontinuierlich (mit Ausnahme der Verrücktheit von bool).
Der Kommentar, den ich hinzufügen wollte, ist, dass, wenn Sie den Vektor einfügen oder löschen, was dazu führen könnte, dass der Vektor seinen Speicher neu zuweist, alle Ihre gespeicherten Zeiger und Iteratoren ungültig werden.

Motti
Tatsächlich garantiert die Norm, dass a vector
ist kontinuierlich im Gedächtnis und das &a[0]
kann an a weitergegeben werden C
Funktion, die ein Array erwartet.
Die Ausnahme von dieser Regel ist vector<bool>
die nur ein Bit pro verwendet bool
Obwohl es einen kontinuierlichen Speicher hat, kann es nicht als verwendet werden bool*
(Dies wird allgemein als falsche Optimierung und Fehler angesehen).
Übrigens, warum verwendest du keine Iteratoren? Dafür sind sie da.
Wie andere schon gesagt haben, vector
verwendet intern ein zusammenhängendes Array von Objekten. Zeiger auf dieses Array sollten immer dann als ungültig behandelt werden, wenn eine nicht konstante Elementfunktion IIRC aufgerufen wird.
Es gibt jedoch eine Ausnahme!!
vector<bool>
verfügt über eine spezielle Implementierung, die darauf ausgelegt ist, Platz zu sparen, sodass jede bool nur ein Bit verwendet. Das zugrunde liegende Array ist kein zusammenhängendes Array aus bool und Array-Arithmetik vector<bool>
funktioniert nicht wie vector<T>
möchten.
(Ich nehme an, es ist auch möglich, dass dies für jede Spezialisierung von Vektoren gilt, da wir immer eine neue implementieren können. std::vector<bool>
ist die einzige, ähm, Standardspezialisierung, bei der einfache Zeigerarithmetik nicht funktioniert.)
Ich habe diesen Thread gefunden, weil ich einen Anwendungsfall habe, bei dem Vektoren mit zusammenhängendem Speicher von Vorteil sind.
Ich lerne, wie man Vertex-Buffer-Objekte in OpenGL verwendet. Ich habe eine Wrapper-Klasse erstellt, die die Pufferlogik enthält, also muss ich nur ein Array von Gleitkommazahlen und ein paar Konfigurationswerte übergeben, um den Puffer zu erstellen. Ich möchte in der Lage sein, einen Puffer aus einer Funktion basierend auf Benutzereingaben zu generieren, sodass die Länge zur Kompilierzeit nicht bekannt ist. So etwas zu tun wäre die einfachste Lösung:
void generate(std::vector<float> v)
{
float f = generate_next_float();
v.push_back(f);
}
Jetzt kann ich die Floats des Vektors als Array an die pufferbezogenen Funktionen von OpenGL übergeben. Dadurch entfällt auch die Notwendigkeit, dass sizeof die Länge des Arrays bestimmt.
Dies ist weitaus besser, als ein riesiges Array zum Speichern der Floats zuzuweisen und zu hoffen, dass ich es groß genug gemacht habe, oder mein eigenes dynamisches Array mit zusammenhängendem Speicher zu erstellen.

Igor
cplusplus.com:
Vektorcontainer werden als dynamische Arrays implementiert; Genau wie bei regulären Arrays werden die Elemente von Vektorcontainern an zusammenhängenden Speicherorten gespeichert, was bedeutet, dass auf ihre Elemente nicht nur mit Iteratoren zugegriffen werden kann, sondern auch mit Offsets auf regulären Zeigern auf Elemente.
Ja, die Elemente eines std::vector sind garantiert zusammenhängend.
9956000cookie-checkSind std::vector Elemente garantiert zusammenhängend?yes
Ich weiß, dass du in Schwierigkeiten steckst, wenn du mutierst
values
darinif
Block. Ich kenne die Antwort auf Ihre Frage nicht, also hinterlasse ich nur einen Kommentar. 🙂– Gregor D
11. Mai 2009 um 17:40 Uhr
@Greg: Was für Probleme – kannst du ein wenig näher darauf eingehen?
– Reunanen
11. Mai 2009 um 17:43 Uhr
Ich nehme an, er meinte, dass das Drücken neuer Werte ein “Realloc” auslösen kann, wodurch das Array ungültig wird.
– Martin Côte
11. Mai 2009 um 17:52 Uhr
Anrufe, die mutieren
values
insbesondere die ihre Größe ändern (z. B.push_back()
), kann eine Neuzuordnung des zugrunde liegenden Vektors veranlassen, die den kopierten Zeiger ungültig machtarray
. Es ist das gleiche Prinzip hinter der Verwendung eines vector::iterator anstelle eines Zeigers in den Vektor. 🙂– Gregor D
11. Mai 2009 um 17:52 Uhr
Ja, ich habe die “s um Werte gesetzt, um klarzustellen, dass ich über die Klasse selbst spreche, nicht über die darin enthaltenen Werte. 🙂 Unglückliche Benennung und all das. Ich glaube nicht, dass es wirklich ein Problem im allgemeinen Fall ist, in dem diese Frage relevant ist – warum sollte jemand einen Zeiger auf den Speicher greifen und dann anfangen, mit dem Vektor herumzuspielen, anstatt den Zeiger zu verwenden? Albernheit.
– Gregor D
11. Mai 2009 um 17:58 Uhr