<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Problem mit ungültigem Iterator]]></title><description><![CDATA[<p>Hallo,</p>
<p>ich habe ein Event-System, bei dem der Benutzer bei verschiedenen Events EventHandler registrieren und entfernen kann. Die EventHandler werden beim Event in einer std::list verwaltet. Wenn ein Event ausgelöst wird, gehe ich die Liste von vorne nach hinten durch und rufe die im EventHandler enthaltene std::function auf. Dabei kann es passieren, dass innerhalb der aufgerufenen Funktion, der gleiche EventHandler aus der Liste gelöscht wird. Problem an der Sache ist, dass sobald die std::function zurückkehrt, der Iterator der aufrufenden Schleife nicht mehr gültig ist. Ich habe mir dazu ein paar Problemlösungen überlegt, die ich aber alle nicht sonderlich toll finde. Deswegen wollte ich fragen, ob hier schonmal jemand ein ähnliches Problem hatte und wie es dort gelöst wurde.</p>
<p>Pseudocode:</p>
<pre><code class="language-cpp">class EventHandler
{
	std::function&lt;void()&gt; handler;
};

class Event
{
	std::list&lt;EventHandler&gt; eventHandler;

	void Add(EventHandler eh)
	{
		eventHandler.push_back(eh);
	}

	void Remove(EventHandler eh)
	{
		eventHandler.remove(eh);
	}

	void Invoke()
	{
		for (auto it = eventHandler.begin(); it != eventHandler.end(); ++it)
			(*it).handler();
	}
};

EventHandler eh([]()
{
	event.Remove(eh);
});
event.Add(eh);
event.Invoke();
</code></pre>
<p>Lösung 1: statt std::list std::vector verwenden und nach einem Funktionsaufruf per size() prüfen, ob sich etwas geändert hat. Beim Vector kann man dann die Zählvariable einfach gleich lassen.<br />
Lösung 2: der EventHandler Klasse ein remove Flag hinzufügen und vor dem Aufrufen prüfen, dass dieses Flag nicht gesetzt ist und nach dem Aufruf prüfen, ob es gesetzt ist und falls ja den EventHandler in der Invoke-Schleife entfernen<br />
Lösung 3: ähnlich wie 2 nur eine weitere Löschliste einführen und dort die zu löschenden EventHandler eintragen. Nach der Invokeschleife diese dann löschen. Problem: vor jedem Aufruf muss geschaut werden, ob der EventHandler in der Löschliste steht und falls ja, nicht mehr aufrufen. Ist zwar sicherlich nicht performancelastig, da die Liste sicher nicht größer wird wie 1-2 Einträge.</p>
<p>Weitere Lösungsmöglichkeiten?</p>
<p>greetz KN4CK3R</p>
]]></description><link>https://www.c-plusplus.net/forum/topic/296963/problem-mit-ungültigem-iterator</link><generator>RSS for Node</generator><lastBuildDate>Fri, 14 Aug 2026 16:15:28 GMT</lastBuildDate><atom:link href="https://www.c-plusplus.net/forum/topic/296963.rss" rel="self" type="application/rss+xml"/><pubDate>Fri, 16 Dec 2011 07:31:07 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to Problem mit ungültigem Iterator on Fri, 16 Dec 2011 07:31:53 GMT]]></title><description><![CDATA[<p>Hallo,</p>
<p>ich habe ein Event-System, bei dem der Benutzer bei verschiedenen Events EventHandler registrieren und entfernen kann. Die EventHandler werden beim Event in einer std::list verwaltet. Wenn ein Event ausgelöst wird, gehe ich die Liste von vorne nach hinten durch und rufe die im EventHandler enthaltene std::function auf. Dabei kann es passieren, dass innerhalb der aufgerufenen Funktion, der gleiche EventHandler aus der Liste gelöscht wird. Problem an der Sache ist, dass sobald die std::function zurückkehrt, der Iterator der aufrufenden Schleife nicht mehr gültig ist. Ich habe mir dazu ein paar Problemlösungen überlegt, die ich aber alle nicht sonderlich toll finde. Deswegen wollte ich fragen, ob hier schonmal jemand ein ähnliches Problem hatte und wie es dort gelöst wurde.</p>
<p>Pseudocode:</p>
<pre><code class="language-cpp">class EventHandler
{
	std::function&lt;void()&gt; handler;
};

class Event
{
	std::list&lt;EventHandler&gt; eventHandler;

	void Add(EventHandler eh)
	{
		eventHandler.push_back(eh);
	}

	void Remove(EventHandler eh)
	{
		eventHandler.remove(eh);
	}

	void Invoke()
	{
		for (auto it = eventHandler.begin(); it != eventHandler.end(); ++it)
			(*it).handler();
	}
};

EventHandler eh([]()
{
	event.Remove(eh);
});
event.Add(eh);
event.Invoke();
</code></pre>
<p>Lösung 1: statt std::list std::vector verwenden und nach einem Funktionsaufruf per size() prüfen, ob sich etwas geändert hat. Beim Vector kann man dann die Zählvariable einfach gleich lassen.<br />
Lösung 2: der EventHandler Klasse ein remove Flag hinzufügen und vor dem Aufrufen prüfen, dass dieses Flag nicht gesetzt ist und nach dem Aufruf prüfen, ob es gesetzt ist und falls ja den EventHandler in der Invoke-Schleife entfernen<br />
Lösung 3: ähnlich wie 2 nur eine weitere Löschliste einführen und dort die zu löschenden EventHandler eintragen. Nach der Invokeschleife diese dann löschen. Problem: vor jedem Aufruf muss geschaut werden, ob der EventHandler in der Löschliste steht und falls ja, nicht mehr aufrufen. Ist zwar sicherlich nicht performancelastig, da die Liste sicher nicht größer wird wie 1-2 Einträge.</p>
<p>Weitere Lösungsmöglichkeiten?</p>
<p>greetz KN4CK3R</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2157525</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2157525</guid><dc:creator><![CDATA[KN4CK3R]]></dc:creator><pubDate>Fri, 16 Dec 2011 07:31:53 GMT</pubDate></item><item><title><![CDATA[Reply to Problem mit ungültigem Iterator on Fri, 16 Dec 2011 07:33:53 GMT]]></title><description><![CDATA[<p>Kleiner Tipp:</p>
<p>In der Schleife in #23,nimm den Pfeiloperator.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2157528</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2157528</guid><dc:creator><![CDATA[[[global:guest]]]]></dc:creator><pubDate>Fri, 16 Dec 2011 07:33:53 GMT</pubDate></item><item><title><![CDATA[Reply to Problem mit ungültigem Iterator on Fri, 16 Dec 2011 07:46:57 GMT]]></title><description><![CDATA[<p>Hacker schrieb:</p>
<blockquote>
<p>Kleiner Tipp:</p>
<p>In der Schleife in #23,nimm den Pfeiloperator.</p>
</blockquote>
<p>Was für ein, für die Problemstellung absolut unrelevanter, &quot;Tipp&quot;.</p>
<p>@TE: Ich würde einen vector an Zeigern auf die zu löschenden Handler anlegen und die Handler dann über die Zeiger nach dem Iterieren löschen.</p>
<p>Was ich aber nicht verstehe: Warum lässt du den Benutzer nicht gleich eine std::function als EventHandler verwenden? Warum muss er die EventHandler-Klasse verwenden?</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2157531</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2157531</guid><dc:creator><![CDATA[314159265358979]]></dc:creator><pubDate>Fri, 16 Dec 2011 07:46:57 GMT</pubDate></item><item><title><![CDATA[Reply to Problem mit ungültigem Iterator on Fri, 16 Dec 2011 07:57:01 GMT]]></title><description><![CDATA[<p>fürs Löschen muss ich die std::functions vergleichen können und std::function lassen sich wohl nicht vergleichen (siehe diverse Threads im Internet). Die EventHandler Klasse beeinhaltet noch eine fortlaufende ID über die ich den Vergleich mache.</p>
<p>Edit:<br />
<a href="http://stackoverflow.com/questions/3629835/why-is-stdfunction-not-equality-comparable" rel="nofollow">http://stackoverflow.com/questions/3629835/why-is-stdfunction-not-equality-comparable</a></p>
<p>Edit2: ich merke gerade .NET macht das wohl auch so:</p>
<pre><code class="language-csharp">private void button1_Click(object sender, EventArgs e)
{
	button1.Click -= ev; // = button2_Click
}

private void button2_Click(object sender, EventArgs e)
{

}
</code></pre>
<p>Beide Funktionen werden beim ersten Klicken ausgeführt, danach nur noch eine. Eigentlich aber nicht intuitiv die Lösung? Wenn ich einen EventHandler entferne, sollte er nicht nochmal aufgerufen werden können danach. Naja egal, dann mach ichs mit ner Löschlist/vector <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f609.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--winking_face"
      title=";)"
      alt="😉"
    /></p>
<p>greetz KN4CK3R</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2157532</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2157532</guid><dc:creator><![CDATA[KN4CK3R]]></dc:creator><pubDate>Fri, 16 Dec 2011 07:57:01 GMT</pubDate></item><item><title><![CDATA[Reply to Problem mit ungültigem Iterator on Fri, 16 Dec 2011 10:07:15 GMT]]></title><description><![CDATA[<p>du könntest es auch so machen, dass du vor dem funktiosn aufruf dir einen temporären iterator erzeugst und den schon eine position weiter gehen lässt. und danach inkrementierst du deinen schleifen iterator nicht sondern weist ihm den temporären zu</p>
<pre><code class="language-cpp">for (auto it = eventHandler.begin(); it != eventHandler.end(); ++it)
{
    auto tmpIt = it++;
    it-&gt;handler();
    it = tmpIt;
}
</code></pre>
<p>iteratoren sind ja nicht die grössten und komplexesten objekte, von daher wird das auch nicht schlimm sein, die zuweisung immer zu machen anstatt einer einfachen inkrementierung</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2157575</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2157575</guid><dc:creator><![CDATA[Skym0sh0]]></dc:creator><pubDate>Fri, 16 Dec 2011 10:07:15 GMT</pubDate></item><item><title><![CDATA[Reply to Problem mit ungültigem Iterator on Fri, 16 Dec 2011 10:55:03 GMT]]></title><description><![CDATA[<p>ohne es jetzt ausprobiert zu haben, der Code scheint Fehler zu enthalten.<br />
Meiner Meinung nach müsste das so aussehen oder?</p>
<pre><code class="language-cpp">for (auto it = eventHandler.begin(); it != eventHandler.end(); )
{
    auto tmpIt = it;
    it++;
    tmpIt-&gt;handler();
}
</code></pre>
<p>Edit: danke für den Hinweis, die Methode sieht am besten aus <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f642.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--slightly_smiling_face"
      title=":)"
      alt="🙂"
    /><br />
<a href="http://ideone.com/V7cpn" rel="nofollow">http://ideone.com/V7cpn</a></p>
<p>greetz KN4CK3R</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2157583</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2157583</guid><dc:creator><![CDATA[KN4CK3R]]></dc:creator><pubDate>Fri, 16 Dec 2011 10:55:03 GMT</pubDate></item><item><title><![CDATA[Reply to Problem mit ungültigem Iterator on Fri, 16 Dec 2011 10:59:49 GMT]]></title><description><![CDATA[<p>ups, ja stimmt jetzt wo dus sagst xD</p>
<p>aber du hast erfasst was ich meinte, und mehr als ein beispiel sollte es nicht sein</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2157598</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2157598</guid><dc:creator><![CDATA[Skym0sh0]]></dc:creator><pubDate>Fri, 16 Dec 2011 10:59:49 GMT</pubDate></item><item><title><![CDATA[Reply to Problem mit ungültigem Iterator on Fri, 16 Dec 2011 11:02:44 GMT]]></title><description><![CDATA[<p>Kann es sein, dass Du sowas wie boost::signals nachbaust?</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2157601</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2157601</guid><dc:creator><![CDATA[Tachyon]]></dc:creator><pubDate>Fri, 16 Dec 2011 11:02:44 GMT</pubDate></item><item><title><![CDATA[Reply to Problem mit ungültigem Iterator on Fri, 16 Dec 2011 11:36:37 GMT]]></title><description><![CDATA[<p>Ich hab´ sowas Ähnliches gebaut, allerdings lege ich nicht die Funktionszeiger in einem Vektor ab, sondern sowas:</p>
<pre><code class="language-cpp">struct EventCallback
{
   bool Removed;
   FuncPtr Callback;
};
</code></pre>
<p>Während des &quot;Feuerns&quot; des Events wird der entsprechende Eintrag nicht aus dem Vektor entfernt, sondern nur das Removed Flag gesetzt. Am Ende der Funktion werden dann alle Einträge entfernt, deren Removed Flag gesetzt ist.<br />
Die Funktion zum Austragen eines Callbacks arbeitet in zwei Modi: Wenn sie aufgerufen wird, während Events abgefeuert werden, markiert sie den entsprechenden Eintrag zum Löschen, ansonsten entfernt sie ihn aus dem Vektor.<br />
Zuletzt musst du vorm Aufrufen der Callbacks noch prüfen, ob das Removed Flag gesetzt ist.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2157616</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2157616</guid><dc:creator><![CDATA[DocShoe]]></dc:creator><pubDate>Fri, 16 Dec 2011 11:36:37 GMT</pubDate></item><item><title><![CDATA[Reply to Problem mit ungültigem Iterator on Fri, 16 Dec 2011 11:43:39 GMT]]></title><description><![CDATA[<p><a class="plugin-mentions-user plugin-mentions-a" href="https://www.c-plusplus.net/forum/uid/4465">@Tachyon</a>: boost::signals kenne ich nur vom Namen her, wie das dort gemacht wird, weiß ich nicht</p>
<p><a class="plugin-mentions-user plugin-mentions-a" href="https://www.c-plusplus.net/forum/uid/18927">@DocShoe</a>: das wäre meine Möglichkeit 2 gewesen, die Lösung von Skym0sh0 gefällt mir allerdings besser, weil sie ohne solch ein Flag auskommt.</p>
<p>greetz KN4CK3R</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2157625</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2157625</guid><dc:creator><![CDATA[KN4CK3R]]></dc:creator><pubDate>Fri, 16 Dec 2011 11:43:39 GMT</pubDate></item><item><title><![CDATA[Reply to Problem mit ungültigem Iterator on Fri, 16 Dec 2011 14:01:17 GMT]]></title><description><![CDATA[<p>ich hab das jetzt einmal testen können und musste feststellen, dass die Version doch nicht so gut ist, wie sie scheint. <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f61e.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--disappointed_face"
      title=":("
      alt="😞"
    /><br />
Wenn das Event entfernt wird, auf das man it in der Zeile auto tmpit = it++ zeigen lässt, dann landet man wieder beim Anfangsproblem. :|<br />
Also dann wohl doch DocShoe's Lösungsansatz.</p>
<p>greetz KN4CK3R</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2157717</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2157717</guid><dc:creator><![CDATA[KN4CK3R]]></dc:creator><pubDate>Fri, 16 Dec 2011 14:01:17 GMT</pubDate></item><item><title><![CDATA[Reply to Problem mit ungültigem Iterator on Fri, 16 Dec 2011 14:25:28 GMT]]></title><description><![CDATA[<p>KN4CK3R schrieb:</p>
<blockquote>
<p>ohne es jetzt ausprobiert zu haben, der Code scheint Fehler zu enthalten.<br />
Meiner Meinung nach müsste das so aussehen oder?</p>
<pre><code class="language-cpp">for (auto it = eventHandler.begin(); it != eventHandler.end(); )
{
    auto tmpIt = it;
    it++;
    tmpIt-&gt;handler();
}
</code></pre>
<p>Edit: danke für den Hinweis, die Methode sieht am besten aus <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f642.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--slightly_smiling_face"
      title=":)"
      alt="🙂"
    /><br />
<a href="http://ideone.com/V7cpn" rel="nofollow">http://ideone.com/V7cpn</a></p>
<p>greetz KN4CK3R</p>
</blockquote>
<p>Setzt aber gültige Iteratoren nach dem erase voraus, funktioniert folglich nur mit Listen. Besser ist es, den Rückgabewert von erase zu verwenden.</p>
<pre><code class="language-cpp">for (auto it = l.begin(); it != l.end();)
        {
                cout &lt;&lt; *it &lt;&lt; endl;
                x++ % 2 == 0 ? it = l.erase(it) : ++it;
        }
</code></pre>
]]></description><link>https://www.c-plusplus.net/forum/post/2157734</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2157734</guid><dc:creator><![CDATA[camper]]></dc:creator><pubDate>Fri, 16 Dec 2011 14:25:28 GMT</pubDate></item><item><title><![CDATA[Reply to Problem mit ungültigem Iterator on Fri, 16 Dec 2011 14:45:03 GMT]]></title><description><![CDATA[<p>Das Problem ist, dass man beim Absetzen der Events keine Informationen darüber bekommt, dass sich jemand aus der Liste austrägt. Damit verlierst du den Rückgabewert von <code>erase</code> und kannst ihn nicht benutzen.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2157743</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2157743</guid><dc:creator><![CDATA[DocShoe]]></dc:creator><pubDate>Fri, 16 Dec 2011 14:45:03 GMT</pubDate></item><item><title><![CDATA[Reply to Problem mit ungültigem Iterator on Fri, 16 Dec 2011 15:02:19 GMT]]></title><description><![CDATA[<p>habs jetzt so gemacht:</p>
<pre><code class="language-cpp">//die Remove Funktion setzt remove auf true
for (auto it = eventHandler.begin(); it != eventHandler.end();)
{
	EventHandler &amp;info = *it;
	if (!info.remove)
	{
		info.eventHandler.GetFunction()(std::forward&lt;T&gt;(param)); //fire event
	}
	if (info.remove)
	{
		it = eventHandler.erase(it);
	}
	else
	{
		++it;
	}
}
</code></pre>
<p>Dieser Version sollte failsafe sein auch wenn im ersten EventHandler alle anderen gelöscht werden würden. Auch das hinzufügen von neuen EventHandlern ist so abgedeckt.</p>
<p>greetz KN4CK3R</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2157757</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2157757</guid><dc:creator><![CDATA[KN4CK3R]]></dc:creator><pubDate>Fri, 16 Dec 2011 15:02:19 GMT</pubDate></item></channel></rss>