<?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[weak_ptr und bind&#x2F;functor mit &amp;quot;nop if expired&amp;quot; semantik]]></title><description><![CDATA[<p>Ich bräuchte für ein Event/Callback-System die Möglichkeit einen Funktor zu basteln, der aus einem Member-Function-Pointer und einen weak_ptr als &quot;this&quot; besteht.<br />
Die Semantik soll dabei sein dass der Aufruf des Funktors einfach nichts tut, falls der weak_ptr expired ist.</p>
<p>Gibt es da irgend etwas fertiges? Oder gibt es eine einfache Möglichkeit das selbst zu programmieren, ohne das ganze Forwarding ala boost::function selbst implementieren zu müssen?</p>
<p>Zur Verfügung stehen mir die Boost 1.38.0 (keine Zeit das Projekt auf die Schnelle noch auf eine neuere Boost umzustellen), und als Compiler kommt Visual C++ 2005 zum Einsatz. Es stehen also auch keine C++0x Features zur Verfügung.</p>
<p>p.S.: was ich nicht dazugeschrieben habe: der weak_ptr muss vor dem Aufruf in einen shared_ptr konvertiert werden (lock()) der dann während des Aufrufs gehalten werden muss, damit garantiert ist, dass das Objekt nicht während des Aufrufs einfach &quot;verschwinden&quot; kann.</p>
]]></description><link>https://www.c-plusplus.net/forum/topic/278769/weak_ptr-und-bind-functor-mit-quot-nop-if-expired-quot-semantik</link><generator>RSS for Node</generator><lastBuildDate>Mon, 24 Aug 2026 20:19:18 GMT</lastBuildDate><atom:link href="https://www.c-plusplus.net/forum/topic/278769.rss" rel="self" type="application/rss+xml"/><pubDate>Sun, 12 Dec 2010 20:30:01 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to weak_ptr und bind&#x2F;functor mit &amp;quot;nop if expired&amp;quot; semantik on Sun, 12 Dec 2010 20:51:02 GMT]]></title><description><![CDATA[<p>Ich bräuchte für ein Event/Callback-System die Möglichkeit einen Funktor zu basteln, der aus einem Member-Function-Pointer und einen weak_ptr als &quot;this&quot; besteht.<br />
Die Semantik soll dabei sein dass der Aufruf des Funktors einfach nichts tut, falls der weak_ptr expired ist.</p>
<p>Gibt es da irgend etwas fertiges? Oder gibt es eine einfache Möglichkeit das selbst zu programmieren, ohne das ganze Forwarding ala boost::function selbst implementieren zu müssen?</p>
<p>Zur Verfügung stehen mir die Boost 1.38.0 (keine Zeit das Projekt auf die Schnelle noch auf eine neuere Boost umzustellen), und als Compiler kommt Visual C++ 2005 zum Einsatz. Es stehen also auch keine C++0x Features zur Verfügung.</p>
<p>p.S.: was ich nicht dazugeschrieben habe: der weak_ptr muss vor dem Aufruf in einen shared_ptr konvertiert werden (lock()) der dann während des Aufrufs gehalten werden muss, damit garantiert ist, dass das Objekt nicht während des Aufrufs einfach &quot;verschwinden&quot; kann.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1993469</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1993469</guid><dc:creator><![CDATA[hustbaer]]></dc:creator><pubDate>Sun, 12 Dec 2010 20:51:02 GMT</pubDate></item><item><title><![CDATA[Reply to weak_ptr und bind&#x2F;functor mit &amp;quot;nop if expired&amp;quot; semantik on Mon, 13 Dec 2010 21:02:18 GMT]]></title><description><![CDATA[<p>*push*</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1994066</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1994066</guid><dc:creator><![CDATA[hustbaer]]></dc:creator><pubDate>Mon, 13 Dec 2010 21:02:18 GMT</pubDate></item><item><title><![CDATA[Reply to weak_ptr und bind&#x2F;functor mit &amp;quot;nop if expired&amp;quot; semantik on Mon, 13 Dec 2010 21:58:37 GMT]]></title><description><![CDATA[<p>Ich denke, das wird in C++98 schwierig wegen des Forwarding-Problems. Also wirst du wahrscheinlich um mehrere <code>operator()</code> -Überladungen nicht herumkommen...</p>
<p>Gibt es irgendwelche Einschränkungen, denen die Memberfunktionen unterliegen? Maximale Parameterzahl, irgendeine Gemeinsamkeit, <code>const</code> -Qualifizierung, oder musst du wirklich 100% generisch arbeiten?</p>
<p>Ich habe zuerst an <code>boost::signal</code> und dessen Combiner gedacht, allerdings müsste dafür der Rückgabetyp immer vom gleichen Typ sein.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1994111</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1994111</guid><dc:creator><![CDATA[Nexus]]></dc:creator><pubDate>Mon, 13 Dec 2010 21:58:37 GMT</pubDate></item><item><title><![CDATA[Reply to weak_ptr und bind&#x2F;functor mit &amp;quot;nop if expired&amp;quot; semantik on Wed, 15 Dec 2010 01:19:03 GMT]]></title><description><![CDATA[<p>Ich muss nicht 100% generisch arbeiten, in diesem Projekt brauche ich nur sehr wenige Signaturen.<br />
Ich habe jetzt eine Klasse gebastelt die als ersten Parameter einen weak_ptr nimmt/erwartet, diesen Lockt, falls expired nix tut, und sonst den darin gespeicherten Funktor aufruft, mit Weiterleitung per <code>const T&amp;</code> .<br />
Für das aktuelle Projekt ausreichend.</p>
<p>Ist allerdings schon das 3. mal oder so, dass ich sowas brauche, und bisher hab' ich entweder drumrum gearbeitet, oder eben eine &quot;good-for-this-project-only&quot; Lösung gestrickt. Daher wäre es fein mal was wiederverwendbares zu basteln.</p>
<p>Was mich noch an der aktuellen Lösung stört: man muss, wenn man einen Member-Funktions-Zeiger an die Wrapper-Klasse übergibt, diesen zuerst mit boost:bind/boost::mem_fn in einen &quot;normalen&quot; Funktor verwandeln, da mein Wrapper keine Member-Funktions-Zeiger verdauen kann.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1994710</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1994710</guid><dc:creator><![CDATA[hustbaer]]></dc:creator><pubDate>Wed, 15 Dec 2010 01:19:03 GMT</pubDate></item><item><title><![CDATA[Reply to weak_ptr und bind&#x2F;functor mit &amp;quot;nop if expired&amp;quot; semantik on Wed, 15 Dec 2010 16:10:46 GMT]]></title><description><![CDATA[<p>Wie willst du denn dann später feststellen, wann der Eintrag in deiner Liste gelöscht werden darf?</p>
<p>Hast du dann nicht zwangsläufig ein Speicherleck?<br />
(Zumindest bis die Liste gelöscht wird und das wird vermutlich nicht so<br />
oft sein bzw. sogar nur bei Beendigung des Programms)</p>
<p>Sollte man in dem Fall nicht über das Design des Programms nachdenken?</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1994997</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1994997</guid><dc:creator><![CDATA[Speicherleck?]]></dc:creator><pubDate>Wed, 15 Dec 2010 16:10:46 GMT</pubDate></item><item><title><![CDATA[Reply to weak_ptr und bind&#x2F;functor mit &amp;quot;nop if expired&amp;quot; semantik on Wed, 15 Dec 2010 22:50:38 GMT]]></title><description><![CDATA[<p>Nexus schrieb:</p>
<blockquote>
<p>Ich habe zuerst an <code>boost::signal</code> und dessen Combiner gedacht, allerdings müsste dafür der Rückgabetyp immer vom gleichen Typ sein.</p>
</blockquote>
<p>Nach meinem Verständnis fordert nop den Rückgabewert <code>void</code> .</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1995158</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1995158</guid><dc:creator><![CDATA[ipsec]]></dc:creator><pubDate>Wed, 15 Dec 2010 22:50:38 GMT</pubDate></item><item><title><![CDATA[Reply to weak_ptr und bind&#x2F;functor mit &amp;quot;nop if expired&amp;quot; semantik on Thu, 16 Dec 2010 00:45:27 GMT]]></title><description><![CDATA[<p>@Speicherleck?:</p>
<p>Welche Liste?</p>
<p>Zur Erklärung:</p>
<p>Bei mir sieht das inetwa so aus:</p>
<pre><code class="language-cpp">class EinDing
{
// ...

    void PostConstructor() // wird aufgerufen wenn schon ein shared_ptr auf &quot;this&quot; existiert
    {
        m_eventConnection = EinEvent.Connect(shared_from_this(), &amp;EinDing::DerHandlerDesDings);
    }

    EventConnection m_eventConnection;
    Irgendwas m_member1;
    Irgendwas m_member2;
}
</code></pre>
<p>EventConnection representiert dabei eben die Connection, d.h. wenn EventConnection sterben geht, dann geht auch die Connection sterben, d.h. der Funktor wird nimmer aufgerufen. Darum kümmert sich der Destruktor von EventConnection.</p>
<p>Ich kann logischerweise keinen &quot;starken&quot; shared_ptr in die EventConnection binden, da sonst ein Zyklus entstehen würde -&gt; leak.</p>
<p>Ein roher Zeiger wäre eine Möglichkeit. Und die wäre in einem Single-Threaded-Modell auch ausreichend (gerade eben so). Hat zwar auch ein paar Tücken, da das Objekt im eigenen Destruktor den Event triggern könnte, was dazu führt dass der eigene Handler nochmals ausgeführt würde - mitten aus dem Destruktor raus. Etwas was man nicht unbedingt erwartet.</p>
<p>Bzw. schlimmer: es könnte sogar der Destruktor eines Members welches vor m_eventConnection zuerstört wird noch den Event triggern, z.B. der Destruktor von m_member1. In dem Moment wurde m_member2 allerdings schon zerstört. Wenn der Handler nun auf m_member2 zugreift ... eieiei. Alles ganz hässlich.<br />
Wenn man davon ausgeht dass Destruktoren keine Events triggern dürfen, könnte man aber damit leben. Bzw. einfach alle EventConnection immer als letzte Member setzen und beten.</p>
<p>Nu gibt's aber mehrere Threads, und die dürfen lustig Events feuern. Und genau das ist der Moment wo der Affe ins Wasser springt.<br />
Während z.B. gerade m_member2 und m_member1 zerstört werden, triggert ein anderer Thread den Event. m_eventConnection wurde noch nicht zerstört, die Connection besteht noch, der Handler wird noch aufgerufen.<br />
Und zwar im &quot;event-triggernden&quot; Thread, während in einem anderen Thread gerade genüsslich das Objekt zerstört wird. -&gt; BUMM</p>
<p>Wenn der Handler nun allerdings folgendes macht...</p>
<pre><code class="language-cpp">void HandlerWrapper(weak_ptr&lt;T&gt; const&amp; that, int blah)
{
    shared_ptr&lt;T&gt; strongThat = that.lock();
    if (strongThat)
        strongThat-&gt;Handler(blah);
}
</code></pre>
<p>...ist das Problem gegessen.</p>
<p>Der Destruktor von EinDing kann ja erst loslaufen wenn (nachdem) bereits KEIN shared_ptr mehr auf das Objekt existiert. Ab dem Moment wird that.lock() einen &quot;leeren&quot; shared_ptr zurückliefern, und der Handler wird nicht mehr ausgeführt.<br />
Wird der Event allerdings kurz davor getriggert, dann hält der shared_ptr in der Handler-Wrapper Funktion das Objekt am Leben, bis der Event fertig ausgefürht wurde. -&gt; Problem gelöst</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1995193</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1995193</guid><dc:creator><![CDATA[hustbaer]]></dc:creator><pubDate>Thu, 16 Dec 2010 00:45:27 GMT</pubDate></item><item><title><![CDATA[Reply to weak_ptr und bind&#x2F;functor mit &amp;quot;nop if expired&amp;quot; semantik on Thu, 16 Dec 2010 00:48:48 GMT]]></title><description><![CDATA[<p>ipsec schrieb:</p>
<blockquote>
<p>Nexus schrieb:</p>
<blockquote>
<p>Ich habe zuerst an <code>boost::signal</code> und dessen Combiner gedacht, allerdings müsste dafür der Rückgabetyp immer vom gleichen Typ sein.</p>
</blockquote>
<p>Nach meinem Verständnis fordert nop den Rückgabewert <code>void</code> .</p>
</blockquote>
<p>In meinen Fall ganz klar: ja.<br />
Theoretisch könnte man NOP zu &quot;if expired return default&quot; umdeuten, wenn man NOP sehr weit auslegt.</p>
<p>Wobei...<br />
Ich hab' mir die Doku der Boost.signals und Boost.signals2 angesehen. So wie ich das verstehe können die das Problem beide nicht alleine lösen, also nicht ohne dass man wieder selbst dafür sorgt dass es geht.</p>
<p>Mal ganz davon abgesehen dass die Boost.signals schonmal sowieso nicht threadsafe ist, und die signals2 nicht in Frage kommt, da sie in der 1.38er Boost noch nicht drinnen ist/war.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1995194</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1995194</guid><dc:creator><![CDATA[hustbaer]]></dc:creator><pubDate>Thu, 16 Dec 2010 00:48:48 GMT</pubDate></item><item><title><![CDATA[Reply to weak_ptr und bind&#x2F;functor mit &amp;quot;nop if expired&amp;quot; semantik on Thu, 16 Dec 2010 22:01:44 GMT]]></title><description><![CDATA[<p>[quote=&quot;hustbaer&quot;]</p>
<pre><code class="language-cpp">m_eventConnection = EinEvent.Connect(shared_from_this(), &amp;EinDing::DerHandlerDesDings);
</code></pre>
<p>Was macht denn diese Zeile?<br />
Sie fügt doch einen Listener zu dem Event hinzu, oder?<br />
Wo werden Sie denn gespeichert? In irgendeiner Liste oder Ähnlichem<br />
oder habe ich das Event-System noch nicht verstanden?</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1995572</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1995572</guid><dc:creator><![CDATA[Speicherleck?]]></dc:creator><pubDate>Thu, 16 Dec 2010 22:01:44 GMT</pubDate></item><item><title><![CDATA[Reply to weak_ptr und bind&#x2F;functor mit &amp;quot;nop if expired&amp;quot; semantik on Thu, 16 Dec 2010 22:12:50 GMT]]></title><description><![CDATA[<p>Wenn du sowas eh immer wieder brauchst, könnte sich nicht eine etwas aufwändigere, generische Lösung lohnen? Ist natürlich blöd, dass C++98 keine variablen typsicheren Argumentlisten hat, und du daher das Rad neu erfinden musst. Aber im Endeffekt lohnt es sich vielleicht mehr, diese Funktionalität selbst zu implementieren, als auf Biegen und Brechen Code wiederzuverwenden, mit dem du dann doch Einschränkungen hast.</p>
<p>Wenn ich das richtig sehe, müsstest du neben der Weak-Reference-Logik vor allem mehrere Überladungen von <code>operator()</code> schreiben. Aber das sollte ja nicht unheimlich komplex oder so sein, oder übersehe ich etwas? Falls du <em>Boost.Preprocessor</em> kennst, könntest du damit sogar Codeduplizierung stark einschränken.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1995577</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1995577</guid><dc:creator><![CDATA[Nexus]]></dc:creator><pubDate>Thu, 16 Dec 2010 22:12:50 GMT</pubDate></item><item><title><![CDATA[Reply to weak_ptr und bind&#x2F;functor mit &amp;quot;nop if expired&amp;quot; semantik on Fri, 17 Dec 2010 04:59:07 GMT]]></title><description><![CDATA[<p>Speicherleck? schrieb:</p>
<blockquote>
<p>hustbaer schrieb:</p>
<blockquote>
<pre><code class="language-cpp">m_eventConnection = EinEvent.Connect(shared_from_this(), &amp;EinDing::DerHandlerDesDings);
</code></pre>
</blockquote>
<p>Was macht denn diese Zeile?<br />
Sie fügt doch einen Listener zu dem Event hinzu, oder?<br />
Wo werden Sie denn gespeichert? In irgendeiner Liste oder Ähnlichem<br />
oder habe ich das Event-System noch nicht verstanden?</p>
</blockquote>
<p>Es gibt nicht &quot;das&quot; Event-System, aber wenn du dich darauf beziehst was ich für dieses Project implementiert habe...</p>
<p>Vorweg: <code>Event.Connect</code> gibt bei mir einen <code>shared_ptr&lt;EventConnection&gt;</code> zurück, nicht direkt ein <code>EventConnection</code> Objekt. Mein Beispiel war also in dem Punkt vereinfacht.</p>
<p><code>Event.Connect</code> erstellt ein neues <code>EventConnection</code> Objekt, welches eine Kopie des übergebenen Handlers (Funktors) speichert. Ownership übernimmt dabei sofort ein <code>shared_ptr</code> , und zwar einer mit einem speziellen Deleter. Dann wir ein <code>weak_ptr</code> auf das <code>EventConnection</code> Objekt in einer internen Liste des Events eingetragen.<br />
Der <code>shared_ptr</code> wird schliesslich an den Aufrufer zurückgegeben.</p>
<p>Wenn der Aufrufer die Connection auflösen möchte, gibt er einfach den <code>shared_ptr</code> frei. Der Deleter sorgt dabei dafür dass das <code>EventConnection</code> Objekt wieder aus der internen Liste des Events ausgetragen wird, bevor es gelöscht wird.</p>
<p>Und bevor der Handler eines <code>EventConnection</code> ausgefürht wird, wird der <code>weak_ptr</code> erstmal gelockt. Der so erhaltene <code>shared_ptr</code> wird dann gehalten bis der Handler fertig ausgeführt wurde.</p>
<p>Im Prinzip alles sehr ähnlich dem was Boost.Signals2 macht.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1995626</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1995626</guid><dc:creator><![CDATA[hustbaer]]></dc:creator><pubDate>Fri, 17 Dec 2010 04:59:07 GMT</pubDate></item></channel></rss>