<?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[Designfrage - Menge als Rückgabewert]]></title><description><![CDATA[<p>Moin Leute,</p>
<p>Es gibt da ein Problem, dass in letzter zeit immer mehr an mir nagt: wie gibt man am geschicktesten in C++ eine Menge von Ausgabewerten zurück?<br />
In meinem konkreten Fall habe ich das Problem, dass ich ein Bild analysiere und das Ergebnis eine ziemlich lange Liste von Vektoren ist. Diese wird dann von späteren Modulen weiterverarbeitet. Zusätzliche Anforderung ist, dass jedes Modul problemlos ausgetauscht werden kann, ohne dass es sich auf andere Module auswirkt.</p>
<p>Konkret sähe das Beispiel und die Lösungen die mir einfallen, so aus:</p>
<pre><code class="language-cpp">//Ansatz 1: direkte Rückgabe
//Nachteil: Rückgabe als Wert, Bindung an vector
class Foo
{
    public:
        std::vector&lt;Vector&gt; bar(Image image);
};
//Ansatz 2: Als Parameter
//Nachteil: Bindung an vector
class Foo
{
    public:
        void bar(Image image,std::vector&lt;Vector&gt;&amp; container);
};
//Ansatz3: Als templateparameter
//Nachteil: Ich kann intern nicht die Datenstruktur so wählen, 
//wie ich sie zur Berechnung brauche sondern muss drauf
//Vertrauen, dass der Nutzer des Moduls mir das gibt was ich brauche
class Foo
{
    public:
        template&lt;class T&gt;
        void bar(Image image,Container&amp; container);
};
//Ansatz4: Datenstruktur als Member und anbieten eines Iteratorinterfaces
//Nachteil: unschön. Allerdings die flexibelste Lösung
class Foo
{
    private:
        std::vector&lt;Vector&gt; container;
    public:
        void bar(Image image);

        std::vector&lt;Vector&gt;::const_iterator begin()const;
        std::vector&lt;Vector&gt;::const_iterator end()const;
};
</code></pre>
<p>Momentan favorisiere ich Lösung 4, weil ich so intern dem Modul jede Datenstruktur erlauben kann, ohne dass dies nach außen hin zu Änderungen führt. Fällt jemandem noch etwas besseres ein?</p>
]]></description><link>https://www.c-plusplus.net/forum/topic/245514/designfrage-menge-als-rückgabewert</link><generator>RSS for Node</generator><lastBuildDate>Fri, 18 Sep 2026 14:42:02 GMT</lastBuildDate><atom:link href="https://www.c-plusplus.net/forum/topic/245514.rss" rel="self" type="application/rss+xml"/><pubDate>Wed, 15 Jul 2009 06:01:23 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to Designfrage - Menge als Rückgabewert on Wed, 15 Jul 2009 06:01:48 GMT]]></title><description><![CDATA[<p>Moin Leute,</p>
<p>Es gibt da ein Problem, dass in letzter zeit immer mehr an mir nagt: wie gibt man am geschicktesten in C++ eine Menge von Ausgabewerten zurück?<br />
In meinem konkreten Fall habe ich das Problem, dass ich ein Bild analysiere und das Ergebnis eine ziemlich lange Liste von Vektoren ist. Diese wird dann von späteren Modulen weiterverarbeitet. Zusätzliche Anforderung ist, dass jedes Modul problemlos ausgetauscht werden kann, ohne dass es sich auf andere Module auswirkt.</p>
<p>Konkret sähe das Beispiel und die Lösungen die mir einfallen, so aus:</p>
<pre><code class="language-cpp">//Ansatz 1: direkte Rückgabe
//Nachteil: Rückgabe als Wert, Bindung an vector
class Foo
{
    public:
        std::vector&lt;Vector&gt; bar(Image image);
};
//Ansatz 2: Als Parameter
//Nachteil: Bindung an vector
class Foo
{
    public:
        void bar(Image image,std::vector&lt;Vector&gt;&amp; container);
};
//Ansatz3: Als templateparameter
//Nachteil: Ich kann intern nicht die Datenstruktur so wählen, 
//wie ich sie zur Berechnung brauche sondern muss drauf
//Vertrauen, dass der Nutzer des Moduls mir das gibt was ich brauche
class Foo
{
    public:
        template&lt;class T&gt;
        void bar(Image image,Container&amp; container);
};
//Ansatz4: Datenstruktur als Member und anbieten eines Iteratorinterfaces
//Nachteil: unschön. Allerdings die flexibelste Lösung
class Foo
{
    private:
        std::vector&lt;Vector&gt; container;
    public:
        void bar(Image image);

        std::vector&lt;Vector&gt;::const_iterator begin()const;
        std::vector&lt;Vector&gt;::const_iterator end()const;
};
</code></pre>
<p>Momentan favorisiere ich Lösung 4, weil ich so intern dem Modul jede Datenstruktur erlauben kann, ohne dass dies nach außen hin zu Änderungen führt. Fällt jemandem noch etwas besseres ein?</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1743198</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1743198</guid><dc:creator><![CDATA[otze]]></dc:creator><pubDate>Wed, 15 Jul 2009 06:01:48 GMT</pubDate></item><item><title><![CDATA[Reply to Designfrage - Menge als Rückgabewert on Wed, 15 Jul 2009 06:32:46 GMT]]></title><description><![CDATA[<p>Zuerst einmal sollte dein Rückgabeparameter nur bedingt von den Klienten (den weiterverarbeitenden Modulen) abhängig sein. Dann sollte deine Funktion genau eine Aufgabe haben, und diese Aufgabe bestimmt wie der Rückgabetyp aussieht. Du sagst dass da eine Reihe von vectoren bei rauskommt. Wenn die Anzahl und Art fest ist würde ichs einfach über ein struct machen, das die ganzen Rückgabewerte zu einem zusammenfasst.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1743208</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1743208</guid><dc:creator><![CDATA[pumuckl]]></dc:creator><pubDate>Wed, 15 Jul 2009 06:32:46 GMT</pubDate></item><item><title><![CDATA[Reply to Designfrage - Menge als Rückgabewert on Wed, 15 Jul 2009 09:07:56 GMT]]></title><description><![CDATA[<p><a class="plugin-mentions-user plugin-mentions-a" href="https://www.c-plusplus.net/forum/uid/9960">@pumuckl</a> Die Funktion hat nur eine Aufgabe, und die Klasse drum herum ist auch nur dazu da, diese Aufgabe zu supporten(am Ende speichert die Klasse im ctor nur ein paar Parameter um den Algorithmus zu konfigurieren).</p>
<p>Das Problem ist, dass das Ergebnis des Algorithmus fast eine beliebig lange Liste sein kann(zwischen 1000 und ~10000 Vektoren). Es muss also schon ein dynamischer Container sein. Auch ist die Datenmenge groß genug, dass ich es mir mehrmals überlegen würde, sie zu kopieren, also fällt ein Container als Rückgabewert raus. Hinzu kommt, dass wenn ein anderer container eingesetzt wird, auch anderer Code direkt davon betroffen ist. Also nicht wirklich die beste Wahl. Alles andere wirkt auf mich aber auch ziemlich unschön.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1743309</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1743309</guid><dc:creator><![CDATA[otze]]></dc:creator><pubDate>Wed, 15 Jul 2009 09:07:56 GMT</pubDate></item><item><title><![CDATA[Reply to Designfrage - Menge als Rückgabewert on Wed, 15 Jul 2009 09:44:43 GMT]]></title><description><![CDATA[<p>otze schrieb:</p>
<blockquote>
<p>Zusätzliche Anforderung ist, dass jedes Modul problemlos ausgetauscht werden kann, ohne dass es sich auf andere Module auswirkt.</p>
</blockquote>
<p>D.h., auch ohne daß andere Module neukompiliert werden müßten?</p>
<p>Die Lösung würde ich davon abhängig machen, wie du dir die Besitzverhältnisse vorstellst. Wenn es sinnvoll ist, nur eine Range auf einen intern verwalteten Container beliebigen Typs zurückzugeben, würde ich mir einen Iterator-Wrapper schreiben, der beliebige Iteratortypen durch ein gemeinsames binäres Interface nutzbar macht, z.B. im Enumerator-Stil:</p>
<pre><code class="language-cpp">template &lt;typename T&gt;
    class IEnumerator
{
public:
    virtual void reset (void) = 0;
    virtual bool moveNext (void) = 0;
    virtual T&amp; get (void) = 0;
};
typedef std::tr1::scoped_ptr &lt;IEnumerator&gt; IEnumeratorPtr;

template &lt;typename T, typename IterT = T*&gt;
    class IteratorEnumerator : public IEnumerator
{
    ...
public:
    IteratorEnumerator (IterT first, IterT last) { ... }
    ...
};

class Foo
{
public:
    IEnumeratorPtr bar (Image image);
};
</code></pre>
<p>Wenn aber das Besitztum des Containers auf den Aufrufer übergehen soll, wäre so etwas vielleicht besser:</p>
<pre><code class="language-cpp">template &lt;typename T, typename ContT&gt;
    class ContainerEnumerator : public IEnumerator
{
private:
    std::tr1::scoped_ptr &lt;ContT&gt; cont;
    ...
public:
    IteratorEnumerator (std::tr1::scoped_ptr &lt;ContT&gt; _cont)
     : cont (_cont)
    { ... }
    ...
};
</code></pre>
]]></description><link>https://www.c-plusplus.net/forum/post/1743331</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1743331</guid><dc:creator><![CDATA[audacia]]></dc:creator><pubDate>Wed, 15 Jul 2009 09:44:43 GMT</pubDate></item><item><title><![CDATA[Reply to Designfrage - Menge als Rückgabewert on Wed, 15 Jul 2009 09:44:50 GMT]]></title><description><![CDATA[<p>otze schrieb:</p>
<blockquote>
<p>Auch ist die Datenmenge groß genug, dass ich es mir mehrmals überlegen würde, sie zu kopieren, also fällt ein Container als Rückgabewert raus.</p>
</blockquote>
<p>Dafür gibt's die &quot;Return Value Optimization&quot;. Der MSVC kann's, der g++ laut kurzer Google-Nachfrage seit Version 3.1. Zum Lesen:<br />
<a href="http://msdn.microsoft.com/en-us/library/ms364057%28VS.80%29.aspx" rel="nofollow">http://msdn.microsoft.com/en-us/library/ms364057%28VS.80%29.aspx</a></p>
]]></description><link>https://www.c-plusplus.net/forum/post/1743332</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1743332</guid><dc:creator><![CDATA[Badestrand]]></dc:creator><pubDate>Wed, 15 Jul 2009 09:44:50 GMT</pubDate></item><item><title><![CDATA[Reply to Designfrage - Menge als Rückgabewert on Wed, 15 Jul 2009 11:38:49 GMT]]></title><description><![CDATA[<p><a class="plugin-mentions-user plugin-mentions-a" href="https://www.c-plusplus.net/forum/uid/13210">@Badestrand</a>: dein Link beschreibt die NRVO. RVO != NRVO. Und RVO würde in diesem Fall auch vermutlich garnix bringen.</p>
<p><a class="plugin-mentions-user plugin-mentions-a" href="https://www.c-plusplus.net/forum/uid/5202">@otze</a>: bist du sicher dass das Kopieren der Liste, im Vergleich mit dem Analysieren des Bildes, überhaupt lange dauert? Wenn das bloss ein paar Prozent sind, dann ... -&gt; wurscht</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1743428</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1743428</guid><dc:creator><![CDATA[hustbaer]]></dc:creator><pubDate>Wed, 15 Jul 2009 11:38:49 GMT</pubDate></item><item><title><![CDATA[Reply to Designfrage - Menge als Rückgabewert on Wed, 15 Jul 2009 11:53:07 GMT]]></title><description><![CDATA[<p>hustbaer schrieb:</p>
<blockquote>
<p><a class="plugin-mentions-user plugin-mentions-a" href="https://www.c-plusplus.net/forum/uid/13210">@Badestrand</a>: dein Link beschreibt die NRVO. RVO != NRVO. Und RVO würde in diesem Fall auch vermutlich garnix bringen.</p>
</blockquote>
<p>Upsi, da hab ich was durcheinandergeworfen. Aber wie wär's mit 'nem aktuellen Compiler, greift bei Objekt-Rückgabe nicht die Move-Semantik?</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1743436</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1743436</guid><dc:creator><![CDATA[Badestrand]]></dc:creator><pubDate>Wed, 15 Jul 2009 11:53:07 GMT</pubDate></item><item><title><![CDATA[Reply to Designfrage - Menge als Rückgabewert on Wed, 15 Jul 2009 11:53:43 GMT]]></title><description><![CDATA[<p>@ audacia: <code>scoped_ptr</code> ist nicht kopierbar (und zudem nicht in TR1).</p>
<p>Was du wahrscheinlich meinst, ist <code>std::auto_ptr</code> .</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1743439</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1743439</guid><dc:creator><![CDATA[Nexus]]></dc:creator><pubDate>Wed, 15 Jul 2009 11:53:43 GMT</pubDate></item><item><title><![CDATA[Reply to Designfrage - Menge als Rückgabewert on Wed, 15 Jul 2009 13:33:00 GMT]]></title><description><![CDATA[<p>Nexus schrieb:</p>
<blockquote>
<p>@ audacia: <code>scoped_ptr</code> ist nicht kopierbar (und zudem nicht in TR1).</p>
</blockquote>
<p>Tatsächlich - das war ein Flüchtigkeitsfehler; ich meinte natürlich <code>shared_ptr&lt;&gt;</code> . Danke für den Hinweis.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1743520</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1743520</guid><dc:creator><![CDATA[audacia]]></dc:creator><pubDate>Wed, 15 Jul 2009 13:33:00 GMT</pubDate></item><item><title><![CDATA[Reply to Designfrage - Menge als Rückgabewert on Wed, 15 Jul 2009 16:19:20 GMT]]></title><description><![CDATA[<p>Badestrand schrieb:</p>
<blockquote>
<p>hustbaer schrieb:</p>
<blockquote>
<p><a class="plugin-mentions-user plugin-mentions-a" href="https://www.c-plusplus.net/forum/uid/13210">@Badestrand</a>: dein Link beschreibt die NRVO. RVO != NRVO. Und RVO würde in diesem Fall auch vermutlich garnix bringen.</p>
</blockquote>
<p>Upsi, da hab ich was durcheinandergeworfen. Aber wie wär's mit 'nem aktuellen Compiler, greift bei Objekt-Rückgabe nicht die Move-Semantik?</p>
</blockquote>
<p>Nur wenn die Klasse die als Return-Typ verwendet wird move-semantics unterstützt. Was die std:: Container tun sollten (und in der STD-Lib vom 2010 Beta auch implementiert ist -- GCC weiss ich nicht, vermutlich auch).</p>
<p>Ich denke das wäre eine gute Möglichkeit: sich drauf verlassen dass es eh egal ist, und sobald man einen Compiler hat der r-value refs kann, fällt der (vermutlich minimale) Overhead dann auch noch weg.</p>
<p>Falls man wirklich draufkommt, dass es nicht egal ist, kann man sich immernoch über diverse Workarounds ein &quot;move-by-swap&quot; für die Standard-Container basteln. Siehe boost::move_t&lt;&gt;.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1743659</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1743659</guid><dc:creator><![CDATA[hustbaer]]></dc:creator><pubDate>Wed, 15 Jul 2009 16:19:20 GMT</pubDate></item><item><title><![CDATA[Reply to Designfrage - Menge als Rückgabewert on Wed, 15 Jul 2009 16:27:08 GMT]]></title><description><![CDATA[<p>Andere Möglichkeit wäre, den Container auf dem Heap zu erzeugen und einen Proxy zu schreiben, der die ganzen Implementierungsdetails (was für ein Container es wirklich ist usw.) kapselt. Schreib ein Interface, das den Ansprüchen der Clients genügt und implementiere es so, dass es den Performanceansprüchen genügt (move-Semantik usw.)</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1743670</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1743670</guid><dc:creator><![CDATA[pumuckl]]></dc:creator><pubDate>Wed, 15 Jul 2009 16:27:08 GMT</pubDate></item><item><title><![CDATA[Reply to Designfrage - Menge als Rückgabewert on Wed, 15 Jul 2009 18:55:42 GMT]]></title><description><![CDATA[<p>BTW:</p>
<p>Wenn der Container nur als Ausgabe verwendet würde, d.h. die Funktion da nur reinschreiben muss, dann wäre die Standard-Lösung natürlich nen Output-Iterator zu verwenden.</p>
<p>Wenn die Funktion wirklich den Container braucht, z.B. um nachsehen zu können ob es schon einen Eintrag gibt, dann würde man mit der Output-Iterator Variante natürlich wieder sinnlos Daten kopieren. Ist aber IMO wirklich die Frage ob das nicht egal ist. Vor allem da es dann eine sehr saubere Trennung gäbe.</p>
<p>----</p>
<p>Oder ... ganz doofer Vorschlag:<br />
Du könntest die Funktion als Input-Iterator implementieren (mit lazy evaluation, oder auch ohne) <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f603.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--grinning_face_with_big_eyes"
      title=":D"
      alt="😃"
    /></p>
]]></description><link>https://www.c-plusplus.net/forum/post/1743743</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1743743</guid><dc:creator><![CDATA[hustbaer]]></dc:creator><pubDate>Wed, 15 Jul 2009 18:55:42 GMT</pubDate></item><item><title><![CDATA[Reply to Designfrage - Menge als Rückgabewert on Wed, 15 Jul 2009 18:56:57 GMT]]></title><description><![CDATA[<p>Vielleicht wäre auch <code>std::auto_ptr</code> eine Möglichkeit, Move-Semantik zu erzeugen. Eventuell reicht das ja.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1743744</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1743744</guid><dc:creator><![CDATA[Nexus]]></dc:creator><pubDate>Wed, 15 Jul 2009 18:56:57 GMT</pubDate></item><item><title><![CDATA[Reply to Designfrage - Menge als Rückgabewert on Fri, 17 Jul 2009 13:20:41 GMT]]></title><description><![CDATA[<p>Erstmal Danke für die Antworten. Ich habe leider immer noch keinen Favoriten rauspicken können. Der OutputIterator wäre sicherlich noch eine Idee die zumindest bei einigen Modulen für eine Verbesserung sorgen könnte. Andere wiederum speichern den Container auch intern um ihn zwischen den Aufrufen nur anzupassen, allerdings sollte in diesen Bereichen eigentlich die Datenmenge recht gering sein. Ich denke, ich werde das mal in der Gruppe ansprechen. Bislang sind wir mit dem Design noch nicht wirklich zufrieden <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>
]]></description><link>https://www.c-plusplus.net/forum/post/1744858</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1744858</guid><dc:creator><![CDATA[otze]]></dc:creator><pubDate>Fri, 17 Jul 2009 13:20:41 GMT</pubDate></item></channel></rss>