<?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[Dreierregel - wie am besten implementieren?]]></title><description><![CDATA[<p>Wenn man innerhalb von Klassen mit Pointern arbeitet, muss man ja bei einer Kopie des Objekts eine tiefe Kopie erstellen. Da gibt es die zwei Möglichkeiten Copy-Konstruktor und operator=. So weit, so gut. Im Copy-Konstruktor kann ich ja in der Initialisierungsliste die Dinge kopieren, die 1:1 übernommen werden können und entsprechend im Body die Kopie der anderen Daten vornehmen, falls nötig. Nun gibt es aber wie gesagt noch den operator=. Auch für den muss ich die selbe Logik implementieren wie für den Copy-Konstruktor. Man nehme folgenden Fall als Beispiel:</p>
<pre><code class="language-cpp">class foo
{
    char *c;
};

foo f1, f2;

f1 = f2;
</code></pre>
<p>Hier würde die Adresse von f2.c einfach in f1.c kopiert werden, was aber unter Umständen nicht gewollt ist.</p>
<p>Ich hab von jemandem gehört, dass man es mittels einer Swap-Methode machen soll. Dieses Beispiel hat er mir gegeben:</p>
<pre><code class="language-cpp">struct foo
{
   foo( foo const &amp; f ) {}
   foo &amp; operator=( foo const &amp; f )
   {
      foo tmp( f );
      swap( tmp ); //&lt;-- this calls foo::swap

      return *this;
   }

   void swap( foo &amp; f )
   {
      // swap members here
   }
};
</code></pre>
<p>Zeigt natürlich nur die Struktur und nicht wie es letztendlich implementiert wird. Ich habe mir jetz mal eine kleine abstrakte Klasse geschrieben, von der ich Klassen ableite, die tiefe Kopien benötigen. So sieht sie aus:</p>
<pre><code class="language-cpp">template &lt;class T&gt;
class mxDeep
{
    protected:
        bool bDeleteResources;

    public:
        mxDeep()
            :
                bDeleteResources(true)
        {}

        virtual T &amp;operator=(const T &amp;copy) = 0;
        virtual void swap(const T &amp;copy) = 0;
        virtual void cleanUp() = 0;

        void setResDelete(const bool bDelete)
        {
            this-&gt;bDeleteResources = bDelete;
        }
};
</code></pre>
<p>Ich leite dann eben davon ab und kann so nicht vergessen die benötigten Methoden zu implementieren.</p>
<p>Ist meine Lösung gut oder gibt es eine bessere?</p>
]]></description><link>https://www.c-plusplus.net/forum/topic/262005/dreierregel-wie-am-besten-implementieren</link><generator>RSS for Node</generator><lastBuildDate>Sun, 05 Apr 2026 11:36:03 GMT</lastBuildDate><atom:link href="https://www.c-plusplus.net/forum/topic/262005.rss" rel="self" type="application/rss+xml"/><pubDate>Fri, 26 Feb 2010 21:49:54 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to Dreierregel - wie am besten implementieren? on Fri, 26 Feb 2010 21:49:54 GMT]]></title><description><![CDATA[<p>Wenn man innerhalb von Klassen mit Pointern arbeitet, muss man ja bei einer Kopie des Objekts eine tiefe Kopie erstellen. Da gibt es die zwei Möglichkeiten Copy-Konstruktor und operator=. So weit, so gut. Im Copy-Konstruktor kann ich ja in der Initialisierungsliste die Dinge kopieren, die 1:1 übernommen werden können und entsprechend im Body die Kopie der anderen Daten vornehmen, falls nötig. Nun gibt es aber wie gesagt noch den operator=. Auch für den muss ich die selbe Logik implementieren wie für den Copy-Konstruktor. Man nehme folgenden Fall als Beispiel:</p>
<pre><code class="language-cpp">class foo
{
    char *c;
};

foo f1, f2;

f1 = f2;
</code></pre>
<p>Hier würde die Adresse von f2.c einfach in f1.c kopiert werden, was aber unter Umständen nicht gewollt ist.</p>
<p>Ich hab von jemandem gehört, dass man es mittels einer Swap-Methode machen soll. Dieses Beispiel hat er mir gegeben:</p>
<pre><code class="language-cpp">struct foo
{
   foo( foo const &amp; f ) {}
   foo &amp; operator=( foo const &amp; f )
   {
      foo tmp( f );
      swap( tmp ); //&lt;-- this calls foo::swap

      return *this;
   }

   void swap( foo &amp; f )
   {
      // swap members here
   }
};
</code></pre>
<p>Zeigt natürlich nur die Struktur und nicht wie es letztendlich implementiert wird. Ich habe mir jetz mal eine kleine abstrakte Klasse geschrieben, von der ich Klassen ableite, die tiefe Kopien benötigen. So sieht sie aus:</p>
<pre><code class="language-cpp">template &lt;class T&gt;
class mxDeep
{
    protected:
        bool bDeleteResources;

    public:
        mxDeep()
            :
                bDeleteResources(true)
        {}

        virtual T &amp;operator=(const T &amp;copy) = 0;
        virtual void swap(const T &amp;copy) = 0;
        virtual void cleanUp() = 0;

        void setResDelete(const bool bDelete)
        {
            this-&gt;bDeleteResources = bDelete;
        }
};
</code></pre>
<p>Ich leite dann eben davon ab und kann so nicht vergessen die benötigten Methoden zu implementieren.</p>
<p>Ist meine Lösung gut oder gibt es eine bessere?</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1861923</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1861923</guid><dc:creator><![CDATA[Max0r]]></dc:creator><pubDate>Fri, 26 Feb 2010 21:49:54 GMT</pubDate></item><item><title><![CDATA[Reply to Dreierregel - wie am besten implementieren? on Fri, 26 Feb 2010 22:04:01 GMT]]></title><description><![CDATA[<p>Max0r schrieb:</p>
<blockquote>
<p>Ist meine Lösung gut oder gibt es eine bessere?</p>
</blockquote>
<p>Sie ist nicht allgemeingültig, da man nicht bei jeder Klasse unbedingt eine swap-Methode braucht bzw. eine swap-Methode nicht immer sinnvoll umgesetzt werden kann.<br />
Aber andersrum ist bei Klassen wo es sowieso eine swap-Methode gibt das Copy&amp;Swap-Idiom meist eine sinnvolle Umsetzung für den op=.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1861929</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1861929</guid><dc:creator><![CDATA[pumuckl]]></dc:creator><pubDate>Fri, 26 Feb 2010 22:04:01 GMT</pubDate></item><item><title><![CDATA[Reply to Dreierregel - wie am besten implementieren? on Fri, 26 Feb 2010 22:07:21 GMT]]></title><description><![CDATA[<p>Ja, dass die nicht für jede Klasse gültig ist, ist mir klar. Deswegen hab ich ja dazugeschrieben, dass ich von ihr ableiten will, wenn ich eben tiefe Kopien brauch. Ich hab mich gefragt, ob man dann nicht auch im Copy-Konstruktor statt der Initialisierungsliste im Body swap() aufrufen könnte. Dadurch spart man sich die Redundanz, die man dadurch hat, dass man die Werte einmal in der Initialisierungsliste festlegt und einmal in der swap().</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1861933</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1861933</guid><dc:creator><![CDATA[Max0r]]></dc:creator><pubDate>Fri, 26 Feb 2010 22:07:21 GMT</pubDate></item><item><title><![CDATA[Reply to Dreierregel - wie am besten implementieren? on Fri, 26 Feb 2010 22:19:13 GMT]]></title><description><![CDATA[<p><code>swap()</code> im Kopierkonstruktor ist unsinnig. Mit welchem Objekt willst du da tauschen?</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1861939</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1861939</guid><dc:creator><![CDATA[Nexus]]></dc:creator><pubDate>Fri, 26 Feb 2010 22:19:13 GMT</pubDate></item><item><title><![CDATA[Reply to Dreierregel - wie am besten implementieren? on Fri, 26 Feb 2010 22:35:41 GMT]]></title><description><![CDATA[<p>Nexus schrieb:</p>
<blockquote>
<p><code>swap()</code> im Kopierkonstruktor ist unsinnig. Mit welchem Objekt willst du da tauschen?</p>
</blockquote>
<p>Naja nicht tauschen, sondern vom übergebenen Objekt in das aktuelle schreiben. Muss ja auch net swap sein, sondern evtl. ne Zwischenfunktion, die das übernimmt.</p>
<p><strong>// Edit</strong></p>
<p>Hab halt irgendwie an sowas hier gedacht:</p>
<pre><code class="language-cpp">struct foo
{
    int a, b;
    char *c;

    foo()
        :
            c(NULL)
    {}

    foo(const foo &amp;f)
    {
        this-&gt;swap(f);
    }

    foo &amp;operator=(const foo&amp; f)
    {
        this-&gt;swap(f);

        return *this;
    }

    void swap(const foo &amp;f)
    {
        if (this-&gt;c != NULL)
        {
            delete[] this-&gt;c;
        }

        unsigned int len = strlen(f.c);

        this-&gt;c = new char[len + 1];

        for (unsigned int i = 0; i &lt; len; ++i)
        {
            this-&gt;c[i] = f.c[i];
        }

        this-&gt;c[len] = '\0';

        this-&gt;a = f.a;
        this-&gt;b = f.b;
    }
};

int main()
{
    foo f1, f2;

    f1.a = 1;
    f1.b = 2;
    f1.c = &quot;blabla&quot;;

    f2.a = 3;
    f2.b = 4;
    f2.c = &quot;blabla2&quot;;

    f1 = f2;

    std::cin.get();
}
</code></pre>
<p>Nur fragt sich jetz, ob des ne gute Idee is.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1861940</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1861940</guid><dc:creator><![CDATA[Max0r]]></dc:creator><pubDate>Fri, 26 Feb 2010 22:35:41 GMT</pubDate></item><item><title><![CDATA[Reply to Dreierregel - wie am besten implementieren? on Fri, 26 Feb 2010 22:44:08 GMT]]></title><description><![CDATA[<p>Max0r schrieb:</p>
<blockquote>
<p>Muss ja auch net swap sein, sondern evtl. ne Zwischenfunktion, die das übernimmt.</p>
</blockquote>
<p>Genau. Und diese Funktion heisst Kopierkonstruktor. <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>Du musst eben jede Membervariable einzeln tauschen, wenn du ein exceptionsicheres Swap willst. Darin besteht ja der Trick: Es werden keine ganzen Objekte kopiert, sondern nur Teile davon getauscht. Da dieser Prozess bis auf BuiltIn-Typen rekursiv weitergeführt werden kann und Kopieren von BuiltIns keine Exceptions wirft, kann man Swap exceptionsicher machen.</p>
<p>Mit deinem Code kommst du vom Copy&amp;Swap weg und Exceptions werden wieder zum Problem. Wenn im Zuweisungsoperator die Speicheranforderung fehlschlägt, hast du einen inkonsistenten Objektstatus. Wie willst du ausserdem deine <code>swap()</code> -Funktion (wobei &quot;swap&quot; ein denkbar schlechter Name dafür ist) implementieren, wenn die Klasse grössere Member mit komplexer Kopiersemantik besitzen? Dann kannst du Zuweisungen auch nicht mehr sicher implementieren.</p>
<p>Du solltest dir übrigens unbedingt mal RAII ansehen. STL-Container machen die Implementierung beispielsweise trivial, sicher <strong>und</strong> effizient.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1861946</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1861946</guid><dc:creator><![CDATA[Nexus]]></dc:creator><pubDate>Fri, 26 Feb 2010 22:44:08 GMT</pubDate></item><item><title><![CDATA[Reply to Dreierregel - wie am besten implementieren? on Fri, 26 Feb 2010 22:55:46 GMT]]></title><description><![CDATA[<p>Max0r schrieb:</p>
<blockquote>
<p>Wenn man innerhalb von Klassen mit Pointern arbeitet, muss man ja bei einer Kopie des Objekts eine tiefe Kopie erstellen.</p>
</blockquote>
<p>Nein. Muss man nicht. Kommt drauf an, was Du machen willst. Wenn ich einen Iterator kopiere, dann wird das, worauf der zeigt <em>nicht</em> kopiert.</p>
<p>Max0r schrieb:</p>
<blockquote>
<p>Ist meine Lösung gut [...]?</p>
</blockquote>
<p>Nee, gefällt mir nicht. Viel zu kompliziert.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1861947</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1861947</guid><dc:creator><![CDATA[krümelkacker]]></dc:creator><pubDate>Fri, 26 Feb 2010 22:55:46 GMT</pubDate></item><item><title><![CDATA[Reply to Dreierregel - wie am besten implementieren? on Fri, 26 Feb 2010 22:58:55 GMT]]></title><description><![CDATA[<p>Ich glaub jetz hab ichs verstanden. Ich hab grade <a href="http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Copy-and-swap" rel="nofollow">das</a> und <a href="http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Non-throwing_swap" rel="nofollow">das</a> gelesen. Mir war net klar, dass ja alles getauscht wird und dadurch der Speicher entsprechend freigeräumt wird (falls der Konstruktor richtig implementiert is). Werds mir wohl morgen nochmal anschauen. Danke...</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1861949</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1861949</guid><dc:creator><![CDATA[Max0r]]></dc:creator><pubDate>Fri, 26 Feb 2010 22:58:55 GMT</pubDate></item><item><title><![CDATA[Reply to Dreierregel - wie am besten implementieren? on Fri, 26 Feb 2010 23:52:35 GMT]]></title><description><![CDATA[<p><a class="plugin-mentions-user plugin-mentions-a" href="https://www.c-plusplus.net/forum/uid/23165">@Max0r</a>:<br />
ich möchte dich nur darauf hinweisen, dass du total auf dem holzweg bist (warst) <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="🙂"
    /> die einfachste variante wurde bereits gefunden, und ist nunmal copy &amp; swap.<br />
ok, es kann immer noch was besseres geben wo bloss noch keiner draufgekommen ist, aber ich halte das in dem fall für sehr unwahrscheinlich.</p>
<p>was &quot;kann nicht vergessen zu implementieren&quot; angeht: wenn man es vergessen kann, dann liegt der fehler einen etage tiefer.</p>
<p>wenn es um zeiger geht, dann verwende ich smart-pointer.<br />
entweder shared_ptr oder scoped_ptr.<br />
scoped_ptr ist nicht kopierbar, d.h. man kann auch nicht vergessen den copy-ctor einer klasse zu implementieren die einen scoped_ptr enthält, also gibt es auch kein problem.<br />
destruktor muss man dadurch auch nicht implementieren.</p>
<p>genauso ist es mit anderen dingen: wenn etwas (eine klasse) nicht kopiert werden darf, dann sollte sie auch non-copyable sein. wenn man das so macht, kann man diese klassen, genauso wie scoped_ptr, als pointer verwenden, und trotzdem nie etwas vergessen.</p>
<p>ein hilfsding wie dein mxDeep ist also volkommen unnötig, und schlimmer noch: es versucht das problem an der völlig falschen stelle zu lösen.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1861955</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1861955</guid><dc:creator><![CDATA[hustbaer]]></dc:creator><pubDate>Fri, 26 Feb 2010 23:52:35 GMT</pubDate></item><item><title><![CDATA[Reply to Dreierregel - wie am besten implementieren? on Sat, 27 Feb 2010 05:46:27 GMT]]></title><description><![CDATA[<p>Willkommen</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1861964</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1861964</guid><dc:creator><![CDATA[www]]></dc:creator><pubDate>Sat, 27 Feb 2010 05:46:27 GMT</pubDate></item><item><title><![CDATA[Reply to Dreierregel - wie am besten implementieren? on Sat, 27 Feb 2010 12:55:41 GMT]]></title><description><![CDATA[<p>hustbaer schrieb:</p>
<blockquote>
<p>was &quot;kann nicht vergessen zu implementieren&quot; angeht: wenn man es vergessen kann, dann liegt der fehler einen etage tiefer.</p>
<p>genauso ist es mit anderen dingen: wenn etwas (eine klasse) nicht kopiert werden darf, dann sollte sie auch non-copyable sein. wenn man das so macht, kann man diese klassen, genauso wie scoped_ptr, als pointer verwenden, und trotzdem nie etwas vergessen.</p>
<p>ein hilfsding wie dein mxDeep ist also volkommen unnötig, und schlimmer noch: es versucht das problem an der völlig falschen stelle zu lösen.</p>
</blockquote>
<p>Ich kann dir net ganz folgen. Meine Klasse soll kopierbar sein und dazu muss ich dann copy &amp; swap implementieren, so wie ichs verstanden hab. Wie würdest du jetz sicherstellen, dass operator=, Copy-Ctor und Destruktor implementiert sind (dass du es nicht vergisst), wenn du nicht von einer abstrakten Klasse ableitest, die dich dazu zwingt (ohne shared_ptr und scoped_ptr zu verwenden)?</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1862044</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1862044</guid><dc:creator><![CDATA[Max0r]]></dc:creator><pubDate>Sat, 27 Feb 2010 12:55:41 GMT</pubDate></item><item><title><![CDATA[Reply to Dreierregel - wie am besten implementieren? on Sat, 27 Feb 2010 13:04:14 GMT]]></title><description><![CDATA[<p>Du sollst ja eben gerade sowas scoped_ptr verwenden.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1862047</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1862047</guid><dc:creator><![CDATA[hustbaer]]></dc:creator><pubDate>Sat, 27 Feb 2010 13:04:14 GMT</pubDate></item><item><title><![CDATA[Reply to Dreierregel - wie am besten implementieren? on Sat, 27 Feb 2010 13:59:28 GMT]]></title><description><![CDATA[<p>Max0r schrieb:</p>
<blockquote>
<p>Ich kann dir net ganz folgen. Meine Klasse soll kopierbar sein und dazu muss ich dann copy &amp; swap implementieren, so wie ichs verstanden hab.</p>
</blockquote>
<p>Musst du nicht zwingend, sondern nur, wenn die vom Compiler generierten Funktionen (vor allem Zuweisungsoperator) nicht exceptionsicher sind. Wenn du aber Objekte als Member hast, welche RAII unterstützen (z.B. STL-Container oder Smart-Pointer), tun die automatisch das Richtige. Aber abgesehen davon kann eine <code>swap()</code> -Funktion auch für andere Dinge nützlich sein, weil sie sehr performantes Tauschen erlaubt.</p>
<p>Max0r schrieb:</p>
<blockquote>
<p>Wie würdest du jetz sicherstellen, dass operator=, Copy-Ctor und Destruktor implementiert sind (dass du es nicht vergisst) [...]</p>
</blockquote>
<p>Daran musst du selbst denken, wenn du eine spezielle Kopiersemantik möchtest. Aber das Vergessen ist nicht wirklich ein Problem, sobald du dir der Thematik ein wenig bewusst bist. Versuche einfach, nicht manuell rumzufrickeln wie bei deinem <code>char*</code> -Beispiel. Nimm stattdessen vorgefertigte Lösungen aus der Standardbibliothek (und evtl. Boost), hier z.B. <code>std::string</code> .</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1862066</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1862066</guid><dc:creator><![CDATA[Nexus]]></dc:creator><pubDate>Sat, 27 Feb 2010 13:59:28 GMT</pubDate></item></channel></rss>