Hat std::vector seine / Ihre Adresse ändern? Wie zu vermeiden
Seit dem die vector-Elemente werden zusammenhängend gespeichert, ich denke, es kann nicht die gleiche Adresse nach einiger push_back ist , da der erste zugewiesenen Platz könnte nicht ausreichen.
Arbeite ich an einem code, wo ich eine Referenz auf ein element in einem Vektor, wie:
int main(){
vector<int> v;
v.push_back(1);
int *ptr = &v[0];
for(int i=2; i<100; i++)
v.push_back(i);
cout << *ptr << endl; //?
return 0;
}
Aber es ist nicht unbedingt wahr, dass ptr
enthält einen Verweis auf v[0]
, richtig? Wie wäre ein guter Weg, um zu garantieren?
Meine erste Idee wäre die Verwendung von einem Vektor von Zeigern und dynamischer Allokation. Ich Frage mich, ob es ist ein einfacher Weg, das zu tun?
PS.: Eigentlich bin ich mit einem vector von einer Klasse statt "int", aber ich denke, die Probleme sind die gleichen.
- Warum Holen Sie sich nicht
&v[0]
nur, wenn Sie es brauchen? - Sie halten das index-element anstelle von Zeiger-und dann, um den Zugriff auf() oder operator[]
- Obwohl: es ist nicht explicited oben, in meinem eigentlichen code, den ich nicht sagen kann, die index-Zugriff nicht mehr, wenn ich es brauche.
- Yudakov: Tolle Idee! Leider merkte ich, dass mit diesem Ansatz würde von mir verlangen zu tun, eine Menge von änderungen, da hab ich auch schon verwendet, eine Struktur mit Zeigern in andere Teile des Codes, aber ohne Probleme, da war ich pre-allocating den Vektor.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Nicht Verwendung behalten uns dies zu verschieben, dangling pointer bug - als jemand, habe das gleiche problem, zuckte mit den Schultern, reserviert 1000, dann ein paar Monate später verbrachte Ewigkeiten versucht herauszufinden, einige seltsame Speicher-bug (der Vektor Kapazität überschritten 1000), kann ich Ihnen sagen, dass dies keine robuste Lösung.
Du willst vermeiden Sie die Adresse von Elementen in einem Vektor, wenn überhaupt möglich, eben auch wegen der unvorhersagbaren Natur von Umschichtungen. Wenn Sie zu haben, verwenden Sie Iteratoren anstelle von raw-Adressen, da überprüft STL-Implementierungen wird Ihnen sagen, Wann Sie unwirksam sind, statt von zufälligen Abstürzen.
Die beste Lösung ist die änderung der container:
Können Sie erhöhen die Kapazität der zugrunde liegenden array verwendet, um den Vektor durch den Aufruf der
reserve
member-Funktion:So lange, wie Sie dürfen nicht mehr als 100 Elemente in den Vektor
ptr
auf das erste element.reserve
Reserven mindestens so viel, wie Sie Fragen, können Sie bis zucapacity
Elemente in den Vektor.std::vector<T>
ist garantiert kontinuierliche, aber die Umsetzung ist kostenlos zu reservieren oder freien Speicherplatz auf Operationen ändern der Vektor-Inhalte (Vektor-Iteratoren, die Zeiger oder Referenzen auf Elemente zu undefined sowie).Erreichen Sie Ihre gewünschte Ergebnis, jedoch durch den Aufruf
reserve
. Wenn ich mich Recht erinnere, der standard garantiert, dass keine Umschichtungen erfolgt sind, bis die Größe des Vektors ist größer als die reservierte Kapazität.Generell würde ich vorsichtig sein (kann man schnell gefangen...). Besser verlassen Sie sich nicht auf
std::vector<>::reserve
- und iterator-Persistenz, es sei denn, Sie haben wirklich zu.Andere Möglichkeit Möglichkeit wäre eine Zweck-integrierte smart-pointer, die, statt der Speicherung einer Adresse speichert die Adresse des Vektors selbst zusammen mit dem index des Elements, die Sie interessieren. Es würden dann diese zusammen und erhalten die Adresse des Elements nur, wenn Sie dereferenzieren es, so etwas wie dieses:
Dann Ihre
int *ptr=&v[0];
würde ersetzt werden durch etwas wie:vec_ptr<int> ptr(v,0);
Ein paar Punkte: Erstens, wenn Sie ordnen Sie die Elemente in Ihrem Vektor zwischen der Zeit, die Sie erstellen, die "Zeiger" und die Zeit, die Sie dereferenzieren, wird es nicht mehr finden, um das ursprüngliche element, aber was element passiert, werden an der angegebenen position. Zweitens hat kein range-checking, so dass (zum Beispiel) versucht, das 100th - Element in einem Vektor, enthält nur 50 Punkte geben zu undefiniertem Verhalten.
Wenn Sie nicht brauchen, Ihre Werte zusammenhängend gespeichert, können Sie mit std::deque statt std::vector. Es muss nicht reservieren, aber enthält Elemente, die in mehreren Blöcken von Speicher.
Als James McNellis und Alexander Geßler erklärt,
reserve
ist eine gute Möglichkeit, pre-allocating memory. Aber der Vollständigkeit halber möchte ich hinzufügen, dass der Zeiger gültig bleibt, alle einfügen/entfernen-Operationen auftreten müssen, aus dem Schwanz des Vektors, sonst Element verlagert wird wieder erlöschen Ihrer Zeiger.int *ptr = &v[0];
soll ein bestimmtes Element in der Liste ist, dann ja, es könnte für ungültig erklärt werden, aber wenn es soll das erste Element in der Liste, was auch immer es ist, dann wird es nicht für ungültig erklärt werden.Je nach Ihren Anforderungen und use-case, möchten Sie vielleicht werfen Sie einen Blick auf Boost-Zeiger-Container-Bibliothek.
In Ihrem Fall könnten Sie
boost::ptr_vector<yourClass>
.Stieß ich auf dieses problem auch, und verbrachte einen ganzen Tag nur zu erkennen vector-Adresse geändert und die gespeicherten Adressen hinfällig geworden. Für mein problem, meine Lösung war, dass
Fand ich die folgenden Werke
Aber ich habe nicht herausgefunden, wie Vektor.front() und ich bin mir nicht sicher, ob ich das verwenden soll
Zeiger[i]=indices[i]*sizeof(vector)+(size_t)&Vektor[0] . Ich denke, der Verweis Weg(2) sollte sehr sicher.