2009-07-16 18 views
4

Ich baue eine DLL, die eine andere Anwendung verwenden würde. Ich möchte den aktuellen Zustand einiger Daten global im Speicher der DLL speichern, bevor ich vom Funktionsaufruf zurückkomme, so dass ich den Zustand beim nächsten Aufruf der Funktion wiederverwenden kann.Iteratoren in Containern speichern

Dafür muss ich einige Iteratoren speichern. Ich verwende einen std :: stack, um alle anderen Daten zu speichern, aber ich war mir nicht sicher, ob ich das auch mit den Iteratoren machen könnte.

Ist es sicher, Listen-Iteratoren in Containerklassen zu platzieren? Wenn nicht, könnten Sie eine Möglichkeit vorschlagen, einen Zeiger auf ein Element in einer Liste zu speichern, damit ich es später verwenden kann?

Ich weiß, einen Vektor zu verwenden, um meine Daten anstelle einer Liste zu speichern, hätte mir erlaubt, den Index zu speichern und ihn sehr einfach wiederzuverwenden, aber leider muss ich nur eine std :: list verwenden.

Antwort

5

Ja, es wird gut funktionieren.

Da so viele andere Antworten gehen darüber eine besondere Qualität der Liste Iteratoren zu sein, ich habe darauf hinweisen, dass es mit irgendwelche Iteratoren arbeiten würde, einschließlich Vektor denjenigen. Die Tatsache, dass Vektoriteratoren ungültig werden, wenn der Vektor modifiziert wird, ist für eine Frage, ob es legal ist, Iteratoren in einem anderen Container zu speichern, kaum relevant - sie ist ist.Natürlich kann der Iterator ungültig gemacht werden, wenn Sie etwas tun, was ihn ungültig macht, aber das hat nichts damit zu tun, ob der Iterator in einem Stapel (oder einer anderen Datenstruktur) gespeichert ist oder nicht.

5

Es sollte kein Problem sein, die Iteratoren zu speichern, stellen Sie sicher, dass Sie sie nicht für eine Kopie der Liste verwenden - ein Iterator ist an eine Instanz der Liste gebunden und kann nicht für eine Kopie verwendet werden.

Das heißt, wenn Sie das tun:

std::list<int>::iterator it = myList.begin(); 
std::list<int> c = myList; 

c.insert (it, ...); // Error 

Wie andere bereits erwähnt haben: Natürlich sollten Sie auch nicht den Iterator ungültig durch das spitze zu Element zu entfernen.

0

Die gleiche Regel gilt für einen Iterator, der in einer lokalen Variablen wie in einer langlebigeren Datenstruktur gespeichert ist: Er bleibt gültig, solange der Container dies zulässt.

Für eine Liste bedeutet dies: Solange der Knoten, auf den er zeigt, nicht gelöscht wird, bleibt der Iterator gültig. Offensichtlich wird der Knoten gelöscht, wenn die Liste zerstört wird ...

6

Iteratoren, die aufgelistet werden, werden nur ungültig, wenn die Liste zerstört wird oder das "spitze" Element aus der Liste entfernt wird.

1

Speichern des Iterators für die Liste sollte in Ordnung sein. Es wird nicht ungültig gemacht, es sei denn, Sie entfernen das gleiche Element aus der Liste, für die Sie den Iterator gespeichert haben. Folgende Zitat aus SGI Website:

Listen haben die wichtige Eigenschaft, die Einsetzen und Spleißen nicht Invalidier Iteratoren Elemente aufzulisten, und dass selbst entkräftet Entfernung nur die Iteratoren, die auf die Elemente verweisen, die entfernt werden

Beachten Sie jedoch, dass sich das vorherige und das nächste Element des gespeicherten Iterators ändern können. Aber der Iterator selbst bleibt gültig.

+0

er sagte nichts über die Änderung der Liste, so dass ich nicht sehen, wie Ungültigkeits ein Problem in erster Linie sein könnte. – jalf

-1

Ja. Liste ist der Weg zu gehen.Sie können meine Antwort auf ähnliche Frage beziehen sich hier: What is the lifetime and validity of C++ iterators:

+0

es würde mit jedem Iterator funktionieren, nicht nur Liste. Die Frage sagt nichts über die Änderung der Liste, so dass Lebensdauer oder Gültigkeit nicht wirklich relevant sind – jalf

2

Dies könnte offtopic, aber nur ein Hinweis ...

Seien Sie sich bewusst, dass Ihre Funktion (en)/Datenstruktur wahrscheinlich für Leseoperationen unsichere Thread würde. Es gibt eine Art grundlegende Thread-Sicherheit, bei der Leseoperationen keine Synchronisation erfordern. Wenn Sie den Sate speichern, wie viel der Aufrufer von Ihrer Struktur liest, wird der gesamte Konzept-Thread unsicher und ein wenig unnatürlich zu verwenden sein. Weil niemand annimmt, dass ein Lesevorgang für den Zustand voll ist.

Wenn zwei Threads sie aufrufen, müssen sie entweder die Aufrufe synchronisieren oder Ihre Datenstruktur kann in einem Race-Zustand enden. Das Problem bei einem solchen Design besteht darin, dass beide Threads Zugriff auf eine gemeinsame Synchronisationsvariable haben müssen.

Ich würde vorschlagen, zwei überladene Funktionen zu machen. Beide sind zustandslos, aber einer von ihnen sollte einen Hinweis-Iterator akzeptieren, wo das nächste Lesen/Suchen/Wiederauffinden usw. beginnt. Dies ist z.B. wie Allocator in AWL implementiert ist. Sie können dem Zuweiser einen Hinweiszeiger (Standard 0) übergeben, damit er schneller einen neuen Speicherblock findet.

Grüße,
Ovanes

+0

Danke für den Hinweis, Ovane. Aber das Problem würde in meinem Fall nicht auftreten, weil der Status für jeden Thread an einem separaten Ort gespeichert wird. Nur ein Thread würde gleichzeitig aus den Containern lesen. Ich bin mir nicht sicher, ob ich die überladenen Funktionen komplett verstehe, ich werde über Allocators lesen müssen, aber danke für den Vorschlag auch. Das klingt interessant – Sahas