<?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[Threads aus dem Konstruktor starten und Instanzen in Vector speichern]]></title><description><![CDATA[<p>Hallo zusammen,</p>
<p>ich habe mich heute relativ lange in folgender Situation verrannt:<br />
Ich habe eine Klasse geschrieben, deren Konstruktor unter anderem einen neuen Thread startet um ein paar asynchrone Initialisierungen vorzunehmen.</p>
<p>Von dieser Klasse habe ich in einer Schleife ein paar Instanzen erstellt und diese einem Vector mit push_back() übergeben. Bei diesem push_back() werden die Instanzen allerdings kopiert und am Ende des Schleifenkopfes wird das ursprüngliche Objekt gelöscht, weil es nur lokal war und ich die Instanz nicht mit new erstellt hatte.</p>
<p>Zur Verdeutlichung das Ganze kurz im Code:</p>
<pre><code>#include &lt;thread&gt;
#include &lt;chrono&gt;
#include &lt;iostream&gt;
#include &lt;vector&gt;

using namespace std;

class MyClass
{
public:
  MyClass()
  {
    callingMethod(); 
  }
  void callingMethod()
  {
    thread myThread = thread(&amp;MyClass::methodForMyThread, this);
    myThread.detach();
  }

private:
  void methodForMyThread()
  {
    this_thread::sleep_for(chrono::milliseconds(100));
    cout&lt;&lt;this&lt;&lt;endl;            // Bis wir hier angekommen sind, wurde this
                                 // schon freigegeben und wieder überschrieben.
                                 // Deshalb bekommen wir zweimal die gleiche
                                 // Adresse auf der Kommandozeile zu sehen.
  }
};

int main()
{
  vector&lt;MyClass&gt; myVec;
  for( int i = 0; i&lt;2; i++ )
  {
    MyClass c = MyClass();       // Die Instanz wird nur lokal angelegt
    myVec.push_back(c);          // Die Instanz wird in den Vektor kopiert
  }                              // Das Objekt c wird freigegeben, obwohl der
                                 // Extra-Thread noch nicht fertig gelaufen is.

  this_thread::sleep_for(chrono::milliseconds(1000)); // alle zum Ende kommen lassen
  cout&lt;&lt;&quot;Ende&quot;&lt;&lt;endl;
  return 0;
}
</code></pre>
<p>Meine Frage ist nun: Wie verhindert man sowas &quot;ordentlich&quot;? Niemals im Konstruktor neue Threads starten? Oder ist es überhaupt Käse, innerhalb einer Methode einen neuen Thread zu starten? Wie würde man es sonst machen? Oder alle Threads im Destruktor joinen?</p>
<p>Also die konkrete Anwendung wäre: Ich möchte im Konstruktor (und auch später) von außerhalb Daten abrufen, und diese mit Daten aus meinem Objekt abgleichen. Ich möchte aber nicht jedes Mal das ganze Programm lahmlegen, bis eine Antwort kommt, sondern stattdessen die Anfrage abschicken, einen inneren Zustand auf &quot;nicht synchron&quot; setzen und wenn die Antwort kommt, den Zustand entsprechend wieder auf &quot;synchron&quot; setzen.<br />
Und in meinem jugendlichen Leichtsinn dachte ich mir, mache ich halt einen Extra-Thread, der kann dann warten bis die Antwort kommt. Mit ein bisschen Schönheitskorrektur funktioniert das auch (jetzt wo ich weiß, was der Fehler war), aber vielleicht ist es ja trotzdem keine gute Idee.</p>
<p>Gibt es eigentlich auch andere Klassen als meine, die nach dem Konstruktoraufruf nicht mehr kopiert werden dürfen? Und wenn ja, wie geht man damit um?</p>
<p>Danke im Voraus für eure Antworten!</p>
<p>Viele Grüße<br />
David</p>
]]></description><link>https://www.c-plusplus.net/forum/topic/331562/threads-aus-dem-konstruktor-starten-und-instanzen-in-vector-speichern</link><generator>RSS for Node</generator><lastBuildDate>Sun, 26 Apr 2026 19:35:51 GMT</lastBuildDate><atom:link href="https://www.c-plusplus.net/forum/topic/331562.rss" rel="self" type="application/rss+xml"/><pubDate>Fri, 06 Mar 2015 18:53:42 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to Threads aus dem Konstruktor starten und Instanzen in Vector speichern on Fri, 06 Mar 2015 18:53:42 GMT]]></title><description><![CDATA[<p>Hallo zusammen,</p>
<p>ich habe mich heute relativ lange in folgender Situation verrannt:<br />
Ich habe eine Klasse geschrieben, deren Konstruktor unter anderem einen neuen Thread startet um ein paar asynchrone Initialisierungen vorzunehmen.</p>
<p>Von dieser Klasse habe ich in einer Schleife ein paar Instanzen erstellt und diese einem Vector mit push_back() übergeben. Bei diesem push_back() werden die Instanzen allerdings kopiert und am Ende des Schleifenkopfes wird das ursprüngliche Objekt gelöscht, weil es nur lokal war und ich die Instanz nicht mit new erstellt hatte.</p>
<p>Zur Verdeutlichung das Ganze kurz im Code:</p>
<pre><code>#include &lt;thread&gt;
#include &lt;chrono&gt;
#include &lt;iostream&gt;
#include &lt;vector&gt;

using namespace std;

class MyClass
{
public:
  MyClass()
  {
    callingMethod(); 
  }
  void callingMethod()
  {
    thread myThread = thread(&amp;MyClass::methodForMyThread, this);
    myThread.detach();
  }

private:
  void methodForMyThread()
  {
    this_thread::sleep_for(chrono::milliseconds(100));
    cout&lt;&lt;this&lt;&lt;endl;            // Bis wir hier angekommen sind, wurde this
                                 // schon freigegeben und wieder überschrieben.
                                 // Deshalb bekommen wir zweimal die gleiche
                                 // Adresse auf der Kommandozeile zu sehen.
  }
};

int main()
{
  vector&lt;MyClass&gt; myVec;
  for( int i = 0; i&lt;2; i++ )
  {
    MyClass c = MyClass();       // Die Instanz wird nur lokal angelegt
    myVec.push_back(c);          // Die Instanz wird in den Vektor kopiert
  }                              // Das Objekt c wird freigegeben, obwohl der
                                 // Extra-Thread noch nicht fertig gelaufen is.

  this_thread::sleep_for(chrono::milliseconds(1000)); // alle zum Ende kommen lassen
  cout&lt;&lt;&quot;Ende&quot;&lt;&lt;endl;
  return 0;
}
</code></pre>
<p>Meine Frage ist nun: Wie verhindert man sowas &quot;ordentlich&quot;? Niemals im Konstruktor neue Threads starten? Oder ist es überhaupt Käse, innerhalb einer Methode einen neuen Thread zu starten? Wie würde man es sonst machen? Oder alle Threads im Destruktor joinen?</p>
<p>Also die konkrete Anwendung wäre: Ich möchte im Konstruktor (und auch später) von außerhalb Daten abrufen, und diese mit Daten aus meinem Objekt abgleichen. Ich möchte aber nicht jedes Mal das ganze Programm lahmlegen, bis eine Antwort kommt, sondern stattdessen die Anfrage abschicken, einen inneren Zustand auf &quot;nicht synchron&quot; setzen und wenn die Antwort kommt, den Zustand entsprechend wieder auf &quot;synchron&quot; setzen.<br />
Und in meinem jugendlichen Leichtsinn dachte ich mir, mache ich halt einen Extra-Thread, der kann dann warten bis die Antwort kommt. Mit ein bisschen Schönheitskorrektur funktioniert das auch (jetzt wo ich weiß, was der Fehler war), aber vielleicht ist es ja trotzdem keine gute Idee.</p>
<p>Gibt es eigentlich auch andere Klassen als meine, die nach dem Konstruktoraufruf nicht mehr kopiert werden dürfen? Und wenn ja, wie geht man damit um?</p>
<p>Danke im Voraus für eure Antworten!</p>
<p>Viele Grüße<br />
David</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2445721</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2445721</guid><dc:creator><![CDATA[NoreSoft]]></dc:creator><pubDate>Fri, 06 Mar 2015 18:53:42 GMT</pubDate></item><item><title><![CDATA[Reply to Threads aus dem Konstruktor starten und Instanzen in Vector speichern on Fri, 06 Mar 2015 18:56:31 GMT]]></title><description><![CDATA[<p>Move-Constructor und dann in den Vector herein-moven oder aber mit emplace_back gleich &quot;in place&quot; erstellen.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2445723</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2445723</guid><dc:creator><![CDATA[tkausl]]></dc:creator><pubDate>Fri, 06 Mar 2015 18:56:31 GMT</pubDate></item><item><title><![CDATA[Reply to Threads aus dem Konstruktor starten und Instanzen in Vector speichern on Fri, 06 Mar 2015 19:22:26 GMT]]></title><description><![CDATA[<p>tkausl schrieb:</p>
<blockquote>
<p>Move-Constructor und dann in den Vector herein-moven oder aber mit emplace_back gleich &quot;in place&quot; erstellen.</p>
</blockquote>
<p>Dann aber vorher ein entprechendes <code>reserve()</code> , sonst passiert das gleiche.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2445727</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2445727</guid><dc:creator><![CDATA[Caligulaminus]]></dc:creator><pubDate>Fri, 06 Mar 2015 19:22:26 GMT</pubDate></item><item><title><![CDATA[Reply to Threads aus dem Konstruktor starten und Instanzen in Vector speichern on Fri, 06 Mar 2015 19:24:35 GMT]]></title><description><![CDATA[<p>Caligulaminus schrieb:</p>
<blockquote>
<p>tkausl schrieb:</p>
<blockquote>
<p>Move-Constructor und dann in den Vector herein-moven oder aber mit emplace_back gleich &quot;in place&quot; erstellen.</p>
</blockquote>
<p>Dann aber vorher ein entprechendes <code>reserve()</code> , sonst passiert das gleiche.</p>
</blockquote>
<p>Oh stimmt, move-constructor wäre halt schon gut in dem fall. Für sowas würde ich dann sogar den Copy-Constructor deleten oder zumindest als explicit deklarieren.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2445728</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2445728</guid><dc:creator><![CDATA[tkausl]]></dc:creator><pubDate>Fri, 06 Mar 2015 19:24:35 GMT</pubDate></item><item><title><![CDATA[Reply to Threads aus dem Konstruktor starten und Instanzen in Vector speichern on Fri, 06 Mar 2015 19:26:27 GMT]]></title><description><![CDATA[<p>Trotz des schon gesagtem solltest du den Thread im Dtor joinen:</p>
<pre><code>{
  MyClass c;
}
// c wurde gelöscht, ggf noch bevor der Thread (der eine member-fkt aufruft) fertig ist
</code></pre>
]]></description><link>https://www.c-plusplus.net/forum/post/2445729</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2445729</guid><dc:creator><![CDATA[Jockelx]]></dc:creator><pubDate>Fri, 06 Mar 2015 19:26:27 GMT</pubDate></item><item><title><![CDATA[Reply to Threads aus dem Konstruktor starten und Instanzen in Vector speichern on Fri, 06 Mar 2015 19:50:02 GMT]]></title><description><![CDATA[<p>NoreSoft schrieb:</p>
<blockquote>
<p>Meine Frage ist nun: Wie verhindert man sowas &quot;ordentlich&quot;? Niemals im Konstruktor neue Threads starten?</p>
</blockquote>
<p>Nö. Ganz einfach: vergiss einfach dass es die Funktion <code>detach()</code> gibt.<br />
Der Thread wird dann zu nem Member, und wenn du dann vergisst den im dtor zu joinen, dann merkst du das ganz schnell beim Testen.<br />
=&gt; Tadaa, Problem gelöst.</p>
<p>ps: Und natürlich: Objekte die Threads &quot;besitzen&quot; sind typischerweise non-copyable und non-movable.<br />
Wobei der Compiler das nicht unbedingt &quot;sieht&quot;, d.h. du musst den Copy-Ctor und Move-Ctor u.U. selbst deleten.</p>
<p>Und warum ist das so? Ganz einfach: weil der Thread mit nem fix in seinen Funktor reinkodierten &quot;this&quot; läuft, und daher darf sich &quot;this&quot; auch nicht ändern. =&gt; <code>move</code> nicht möglich.<br />
Und das Kopieren eines Objekts welches nen eigenen Thread hat ist meist schon semantisch völliger Quatsch.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2445731</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2445731</guid><dc:creator><![CDATA[hustbaer]]></dc:creator><pubDate>Fri, 06 Mar 2015 19:50:02 GMT</pubDate></item><item><title><![CDATA[Reply to Threads aus dem Konstruktor starten und Instanzen in Vector speichern on Mon, 09 Mar 2015 10:49:29 GMT]]></title><description><![CDATA[<p>Hallo zusammen,</p>
<p>danke für die vielen schnellen Antworten. <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="🙂"
    /></p>
<p>Also ich fasse nochmal kurz zusammen:</p>
<ol>
<li>
<p>detach() nicht mehr benutzen, stattdessen den Thread als Membervariable halten und spätestens im Dtor joinen.</p>
</li>
<li>
<p>Copy-Ctor löschen, weil das Kopieren eines Objekts, das einen eigenen Thread hat, wenig Sinn macht.</p>
</li>
<li>
<p>Move-Ctor entweder löschen oder darin den eigenen Thread &quot;abhandeln&quot; (das heißt joinen und gegebenenfalls neuen Thread starten).</p>
</li>
</ol>
<p>Für meine Zwecke würde ich den Move- und Copy-Ctor löschen, und um Fehlern beim impliziten Verschieben durch vector aus dem Weg zu gehen würde ich in dem Vektor nicht mehr die Objekte, sondern Zeiger darauf speichern und die Objekte entsprechend auf dem Heap anlegen und an geeigneter Stelle wieder freigeben.<br />
Klingt das eurer Meinung nach sinnvoll?</p>
<p>Viele Grüße<br />
David</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2446023</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2446023</guid><dc:creator><![CDATA[NoreSoft]]></dc:creator><pubDate>Mon, 09 Mar 2015 10:49:29 GMT</pubDate></item><item><title><![CDATA[Reply to Threads aus dem Konstruktor starten und Instanzen in Vector speichern on Mon, 09 Mar 2015 13:05:54 GMT]]></title><description><![CDATA[<p>Vielleicht ist die Boost thread_group was für Dich.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2446036</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2446036</guid><dc:creator><![CDATA[boosty]]></dc:creator><pubDate>Mon, 09 Mar 2015 13:05:54 GMT</pubDate></item><item><title><![CDATA[Reply to Threads aus dem Konstruktor starten und Instanzen in Vector speichern on Mon, 09 Mar 2015 16:31:10 GMT]]></title><description><![CDATA[<p>@boosty<br />
Wie kommst du auf die Idee? Ich sehe hier nichts wo <code>thread_group</code> helfen könnte.</p>
<p><a class="plugin-mentions-user plugin-mentions-a" href="https://www.c-plusplus.net/forum/uid/32300">@NoreSoft</a><br />
Ja, ich denke in diesem Fall wäre das sinnvoll.</p>
<p>NoreSoft schrieb:</p>
<blockquote>
<p>um Fehlern beim impliziten Verschieben durch vector aus dem Weg zu gehen</p>
</blockquote>
<p>Wenn die Klasse keinen Copy-Ctor und keinen Move-Ctor hat, dann kannst du Objekte dieser Klasse sowieso nicht mehr in einen <code>vector</code> stecken. Probier's einfach aus, der Code darf nicht compilieren. Irgendwie logisch, der <code>vector</code> hat dann ja keine Möglichkeit mehr die Elemente rumzuschieben.</p>
<p>NoreSoft schrieb:</p>
<blockquote>
<p>würde ich in dem Vektor nicht mehr die Objekte, sondern Zeiger darauf speichern und die Objekte entsprechend auf dem Heap anlegen und an geeigneter Stelle wieder freigeben.</p>
</blockquote>
<p>Ich würde dir empfehlen das auf jeden Fall nicht manuell zu machen.<br />
Entweder nimm einen speziellen Container ala <code>ptr_vector&lt;Foo&gt;</code> (Boost), oder mach einen <code>vector&lt;unique_ptr&lt;Foo&gt;&gt;</code> . Beide stellen sicher dass die <code>Foo</code> Objekte beim Löschen des Containers automatisch auch gelöscht werden.</p>
<p>Das mit Hand zu machen ist immer fummelig, und wird noch viel fummeliger wenn man versucht auch sämtliche &quot;Spezialfälle&quot; abzudecken.<br />
Wie z.B. den &quot;Spezialfall&quot; dass hier beim Vergrössern des <code>vector</code> eine Exception fliegt (z.B. <code>bad_alloc</code> ):</p>
<pre><code class="language-cpp">myVector.push_back(new Foo()); // potentielles LEAK!!!
</code></pre>
]]></description><link>https://www.c-plusplus.net/forum/post/2446059</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2446059</guid><dc:creator><![CDATA[hustbaer]]></dc:creator><pubDate>Mon, 09 Mar 2015 16:31:10 GMT</pubDate></item><item><title><![CDATA[Reply to Threads aus dem Konstruktor starten und Instanzen in Vector speichern on Mon, 09 Mar 2015 16:59:47 GMT]]></title><description><![CDATA[<p>hustbaer schrieb:</p>
<blockquote>
<p>Das mit Hand zu machen ist immer fummelig, und wird noch viel fummeliger wenn man versucht auch sämtliche &quot;Spezialfälle&quot; abzudecken.<br />
Wie z.B. den &quot;Spezialfall&quot; dass hier beim Vergrössern des <code>vector</code> eine Exception fliegt (z.B. <code>bad_alloc</code> ):</p>
<pre><code class="language-cpp">myVector.push_back(new Foo()); // potentielles LEAK!!!
</code></pre>
</blockquote>
<pre><code class="language-cpp">myVector.reserve(myVector.size()+1);
myVector.push_back(new Foo()); // leakt nie
</code></pre>
<p>Wobei ich mir über bad_alloc eh keine Sorgen machen würde. Tritt das auf, hast du sowieso verloren. Ob da was leakt oder nicht ist dann egal.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2446062</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2446062</guid><dc:creator><![CDATA[fummlus]]></dc:creator><pubDate>Mon, 09 Mar 2015 16:59:47 GMT</pubDate></item><item><title><![CDATA[Reply to Threads aus dem Konstruktor starten und Instanzen in Vector speichern on Mon, 09 Mar 2015 18:15:45 GMT]]></title><description><![CDATA[<p>@fummlus<br />
Mir ist schon klar wie man das beheben kann.<br />
Nur sind das alles dreckige Workarounds - so programmiert man einfach nicht.</p>
<p>OK, klar, man <em>kann</em> so programmieren. Genau so wie man sich jeden Tag mitm Hammer auf den Kopp hauen kann. Es macht nur einfach keinen Sinn.</p>
<p>fummlus schrieb:</p>
<blockquote>
<p>Wobei ich mir über bad_alloc eh keine Sorgen machen würde. Tritt das auf, hast du sowieso verloren. Ob da was leakt oder nicht ist dann egal.</p>
</blockquote>
<p>Same here. Die Sache um die es geht ist viel grundlegender als ein spezieller Fall. Die Überlegung &quot;kann der Fall hier wirklich auftreten, bzw. könnte die restliche Anwendung überhaupt sinnvoll damit umgehen&quot; ist in 99% der Fälle Zeitverschwendung.</p>
<p>Gewöhnt euch an sauber zu programmieren, dann stellen sich diese Fragen erst gar nicht.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2446083</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2446083</guid><dc:creator><![CDATA[hustbaer]]></dc:creator><pubDate>Mon, 09 Mar 2015 18:15:45 GMT</pubDate></item></channel></rss>