<?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[std::distance und size()]]></title><description><![CDATA[<p>Hallo,</p>
<p>angenommen ich will eine Funktion schreiben die unter anderem die Größe eines Containers braucht, etwa eine Mittelwert Funktion. Diese würde ich ungefähr folgendermaßen implementieren:</p>
<pre><code>template &lt;typename iter&gt; auto mean(iter start_, iter end_) -&gt; typename std::remove_reference&lt;decltype(*start_)&gt;::type
{
	typedef typename std::remove_reference&lt;decltype(*start_)&gt;::type T;
	return std::accumulate(start_, end_, T(0))/std::distance(start_, end_);
}
</code></pre>
<p>Meine Bedenken bei diesem Code beziehen sich auf das <code>std::distance</code> .</p>
<p>Dieses hat laut <a href="http://www.cplusplus.com/reference/iterator/distance/" rel="nofollow">Doku</a> nur für Random-Access Iteratoren eine konstante Laufzeit. Wenn ich jetzt also Iteratoren einer <code>std::list</code> übergeben würde, würde ich Performance verschwenden. Denn nach <a href="http://www.cplusplus.com/reference/list/list/begin/" rel="nofollow">hier</a> hat <code>std::list</code> nur bidirectional Iteratoren, während der <code>.size()</code> Zugriff bei list laut <a href="http://www.cplusplus.com/reference/list/list/size/" rel="nofollow">dieser</a> Quelle konstant ist ab C++11.</p>
<p>Das heißt, mit <code>.size()</code> wäre die Funktion wesentlich effizienter als mit <code>std::distance</code> , allerdings kann ich das ja nicht mit Iteratoren verwenden. Die Mittelwert Funktion wäre also nicht für jeden Container optimal, die Abstraktion würde Overhead verursachen.</p>
<p>Wie könnte man das verbessern? Selbst wenn ich einen Container als Template übergeben würde und keine Iteratoren (was an sich schon eine schlechte Lösung wäre), gäbe es das zusätzliche Problem dass kein <code>std::size</code> (in Anlehnung an <code>std::begin</code> ) existiert.</p>
<p>Ein Dilemma?</p>
]]></description><link>https://www.c-plusplus.net/forum/topic/327341/std-distance-und-size</link><generator>RSS for Node</generator><lastBuildDate>Thu, 09 Jul 2026 11:52:19 GMT</lastBuildDate><atom:link href="https://www.c-plusplus.net/forum/topic/327341.rss" rel="self" type="application/rss+xml"/><pubDate>Tue, 05 Aug 2014 14:16:46 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to std::distance und size() on Tue, 05 Aug 2014 14:17:26 GMT]]></title><description><![CDATA[<p>Hallo,</p>
<p>angenommen ich will eine Funktion schreiben die unter anderem die Größe eines Containers braucht, etwa eine Mittelwert Funktion. Diese würde ich ungefähr folgendermaßen implementieren:</p>
<pre><code>template &lt;typename iter&gt; auto mean(iter start_, iter end_) -&gt; typename std::remove_reference&lt;decltype(*start_)&gt;::type
{
	typedef typename std::remove_reference&lt;decltype(*start_)&gt;::type T;
	return std::accumulate(start_, end_, T(0))/std::distance(start_, end_);
}
</code></pre>
<p>Meine Bedenken bei diesem Code beziehen sich auf das <code>std::distance</code> .</p>
<p>Dieses hat laut <a href="http://www.cplusplus.com/reference/iterator/distance/" rel="nofollow">Doku</a> nur für Random-Access Iteratoren eine konstante Laufzeit. Wenn ich jetzt also Iteratoren einer <code>std::list</code> übergeben würde, würde ich Performance verschwenden. Denn nach <a href="http://www.cplusplus.com/reference/list/list/begin/" rel="nofollow">hier</a> hat <code>std::list</code> nur bidirectional Iteratoren, während der <code>.size()</code> Zugriff bei list laut <a href="http://www.cplusplus.com/reference/list/list/size/" rel="nofollow">dieser</a> Quelle konstant ist ab C++11.</p>
<p>Das heißt, mit <code>.size()</code> wäre die Funktion wesentlich effizienter als mit <code>std::distance</code> , allerdings kann ich das ja nicht mit Iteratoren verwenden. Die Mittelwert Funktion wäre also nicht für jeden Container optimal, die Abstraktion würde Overhead verursachen.</p>
<p>Wie könnte man das verbessern? Selbst wenn ich einen Container als Template übergeben würde und keine Iteratoren (was an sich schon eine schlechte Lösung wäre), gäbe es das zusätzliche Problem dass kein <code>std::size</code> (in Anlehnung an <code>std::begin</code> ) existiert.</p>
<p>Ein Dilemma?</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2412106</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2412106</guid><dc:creator><![CDATA[happystudent]]></dc:creator><pubDate>Tue, 05 Aug 2014 14:17:26 GMT</pubDate></item><item><title><![CDATA[Reply to std::distance und size() on Tue, 05 Aug 2014 14:28:42 GMT]]></title><description><![CDATA[<p>An der Laufzeitkomplexität ändert sich natürlich nichts, ist beides <span class="katex"><span class="katex-mathml"><math><semantics><mrow><mrow><mi mathvariant="script">O</mi></mrow><mo>(</mo><mi>n</mi><mo>)</mo></mrow><annotation encoding="application/x-tex">\mathcal{O}(n)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="strut" style="height:0.75em;"></span><span class="strut bottom" style="height:1em;vertical-align:-0.25em;"></span><span class="base textstyle uncramped"><span class="mord textstyle uncramped"><span class="mord mathcal" style="margin-right:0.02778em;">O</span></span><span class="mopen">(</span><span class="mord mathit">n</span><span class="mclose">)</span></span></span></span>. Aber die Liste muss zwei Mal durchlaufen werden was natürlich einen gewissen Overhead mit sich bringt (wobei man beachten muss dass es - im Gegesatz zu Arrays - onehin grauenhaft langsam ist eine verkettete Liste zu durchlaufen).</p>
<p>Die einfachste Lösung, die mir einfällt, ist auf <code>std::accumulate</code> zu verzichten und selber mit einer for-Schleife und einem counter durchzulafen:</p>
<pre><code>counter = 0;
for ( iter it = start_; it != end_; ++it, ++counter )
{
  // sum up
}
</code></pre>
<p>Am Ende der for-Schleife hast du die Anzahl Elemente dann in <code>counter</code> gespeichert und brauchst kein <code>std::distance</code> mehr.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2412108</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2412108</guid><dc:creator><![CDATA[icarus2]]></dc:creator><pubDate>Tue, 05 Aug 2014 14:28:42 GMT</pubDate></item><item><title><![CDATA[Reply to std::distance und size() on Tue, 05 Aug 2014 14:27:46 GMT]]></title><description><![CDATA[<p>Ich denke wenn du auf ganzen Containern arbeiten willst ist die Übergabe eines Containers ok. Wenn du aber einen Algorithmus erstellen will der auf beliebigen Iteratorpaaren funktioniert, nützt dir der size-Aufruf eh nichts, da es ja z.B. auch nur ein Teil einer Liste sein könnte.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2412109</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2412109</guid><dc:creator><![CDATA[TNA]]></dc:creator><pubDate>Tue, 05 Aug 2014 14:27:46 GMT</pubDate></item><item><title><![CDATA[Reply to std::distance und size() on Tue, 05 Aug 2014 14:46:55 GMT]]></title><description><![CDATA[<p>icarus2 schrieb:</p>
<blockquote>
<p>Die einfachste Lösung, die mir einfällt, ist auf <code>std::accumulate</code> zu verzichten und selber mit einer for-Schleife und einem counter durchzulafen:</p>
</blockquote>
<p>Hm Ok, dann werd ichs wohl so machen.</p>
<p>Wollte halt std::accumulate verwenden weil das anscheinend noch irgendwelche internen Optimierungen durchführt die sich mir nicht so ganz erschließen (siehe <a href="http://www.c-plusplus.net/forum/327153" rel="nofollow">hier</a>). Wäre vielleicht ganz gut wenn die ne Überladung dafür schreiben würden die ne counter-Referenz oder so nimmt...</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2412111</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2412111</guid><dc:creator><![CDATA[happystudent]]></dc:creator><pubDate>Tue, 05 Aug 2014 14:46:55 GMT</pubDate></item><item><title><![CDATA[Reply to std::distance und size() on Tue, 05 Aug 2014 14:51:52 GMT]]></title><description><![CDATA[<p>happystudent schrieb:</p>
<blockquote>
<p>Wäre vielleicht ganz gut wenn die ne Überladung dafür schreiben würden die ne counter-Referenz oder so nimmt...</p>
</blockquote>
<p>Es gibt eine Überladung die eine &quot;Binary Operation&quot; nimmt. Da könntest du deinen Counter einbauen, aber ob es den Aufwand wert ist weiß ich nicht.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2412112</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2412112</guid><dc:creator><![CDATA[TNA]]></dc:creator><pubDate>Tue, 05 Aug 2014 14:51:52 GMT</pubDate></item><item><title><![CDATA[Reply to std::distance und size() on Tue, 05 Aug 2014 14:59:51 GMT]]></title><description><![CDATA[<p>mean ist kein besonders gutes Beispiel für eine generische Funktion.</p>
<pre><code class="language-cpp">std::vector&lt;int&gt; v{1,2};
double m = mean(begin(v), end(v));
assert(m == 1.5); // fail!
</code></pre>
<p>Wenn du es doch selber schreibst: <a href="http://www.boost.org/libs/iterator/doc/counting_iterator.html" rel="nofollow">www.boost.org/libs/iterator/doc/counting_iterator.html</a> + std::accumulate/boost::accumulate mit Lamba</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2412114</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2412114</guid><dc:creator><![CDATA[mean_user]]></dc:creator><pubDate>Tue, 05 Aug 2014 14:59:51 GMT</pubDate></item><item><title><![CDATA[Reply to std::distance und size() on Tue, 05 Aug 2014 15:11:19 GMT]]></title><description><![CDATA[<p>mean_user schrieb:</p>
<blockquote>
<pre><code class="language-cpp">assert(m == 1.5); // fail!
</code></pre>
</blockquote>
<p>Der grösste Fail ist dieser Vergleich <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/2412116</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2412116</guid><dc:creator><![CDATA[icarus2]]></dc:creator><pubDate>Tue, 05 Aug 2014 15:11:19 GMT</pubDate></item><item><title><![CDATA[Reply to std::distance und size() on Tue, 05 Aug 2014 15:16:09 GMT]]></title><description><![CDATA[<p>mean_user schrieb:</p>
<blockquote>
<p>mean ist kein besonders gutes Beispiel für eine generische Funktion.</p>
<pre><code class="language-cpp">std::vector&lt;int&gt; v{1,2};
double m = mean(begin(v), end(v));
assert(m == 1.5); // fail!
</code></pre>
</blockquote>
<p>Ja und, warum soll das jetzt irgendwie schlecht sein?</p>
<p>Ist doch klar dass wenn du ints aufaddierst und dann teilst keinen korrekten double Wert kriegst. Generisch heißt doch nicht dass ein Typ (bzw. Ergebnis) beliebig konvertierbar sein muss.</p>
<p>Meiner Meinung nach ist das ein perfektes Beispiel für eine generische Funktion, da sie sowohl den Typen als auch den Container weg abstrahiert, und zwar automatisch und nicht wie etwa <code>std::accumulate</code> durch einen nervigen extra Parameter.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2412117</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2412117</guid><dc:creator><![CDATA[happystudent]]></dc:creator><pubDate>Tue, 05 Aug 2014 15:16:09 GMT</pubDate></item><item><title><![CDATA[Reply to std::distance und size() on Tue, 05 Aug 2014 15:23:21 GMT]]></title><description><![CDATA[<p>Uebergib accumulate halt ne Lambda:</p>
<pre><code>T count = 0;
return accumulate(s, e, T(0), [&amp;](T a, T b){ ++count; return a + b; }) / count;
</code></pre>
]]></description><link>https://www.c-plusplus.net/forum/post/2412119</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2412119</guid><dc:creator><![CDATA[Kellerautomat]]></dc:creator><pubDate>Tue, 05 Aug 2014 15:23:21 GMT</pubDate></item><item><title><![CDATA[Reply to std::distance und size() on Tue, 05 Aug 2014 15:24:47 GMT]]></title><description><![CDATA[<p>*Edit<br />
Hier stand völliger Unsinn.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2412120</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2412120</guid><dc:creator><![CDATA[icarus2]]></dc:creator><pubDate>Tue, 05 Aug 2014 15:24:47 GMT</pubDate></item><item><title><![CDATA[Reply to std::distance und size() on Tue, 05 Aug 2014 15:40:10 GMT]]></title><description><![CDATA[<p>Kellerautomat schrieb:</p>
<blockquote>
<p>Uebergib accumulate halt ne Lambda:</p>
<pre><code>T count = 0;
return accumulate(s, e, T(0), [&amp;](T a, T b){ ++count; return a + b; }) / count;
</code></pre>
</blockquote>
<p>Öhm...</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2412123</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2412123</guid><dc:creator><![CDATA[UB]]></dc:creator><pubDate>Tue, 05 Aug 2014 15:40:10 GMT</pubDate></item><item><title><![CDATA[Reply to std::distance und size() on Tue, 05 Aug 2014 15:40:26 GMT]]></title><description><![CDATA[<p>happystudent schrieb:</p>
<blockquote>
<p>Wollte halt std::accumulate verwenden weil das anscheinend noch irgendwelche internen Optimierungen durchführt die sich mir nicht so ganz erschließen (siehe <a href="http://www.c-plusplus.net/forum/327153" rel="nofollow">hier</a>).</p>
</blockquote>
<p>Ha??</p>
<p>Kellerautomat schrieb:</p>
<blockquote>
<p>lamda</p>
</blockquote>
<p>Keine gute Idee, falls accumulate unerschließliche Optimierungen machen darf.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2412124</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2412124</guid><dc:creator><![CDATA[volkard]]></dc:creator><pubDate>Tue, 05 Aug 2014 15:40:26 GMT</pubDate></item><item><title><![CDATA[Reply to std::distance und size() on Tue, 05 Aug 2014 15:43:02 GMT]]></title><description><![CDATA[<p>UB schrieb:</p>
<blockquote>
<p>Kellerautomat schrieb:</p>
<blockquote>
<p>Uebergib accumulate halt ne Lambda:</p>
<pre><code>T count = 0;
return accumulate(s, e, T(0), [&amp;](T a, T b){ ++count; return a + b; }) / count;
</code></pre>
</blockquote>
<p>Öhm...</p>
</blockquote>
<p>Speicher es halt in ne Variable und gib dann sum / count zurueck. Kommt doch aufs selbe raus <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f644.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--face_with_rolling_eyes"
      title=":rolling_eyes:"
      alt="🙄"
    /></p>
]]></description><link>https://www.c-plusplus.net/forum/post/2412128</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2412128</guid><dc:creator><![CDATA[Kellerautomat]]></dc:creator><pubDate>Tue, 05 Aug 2014 15:43:02 GMT</pubDate></item><item><title><![CDATA[Reply to std::distance und size() on Tue, 05 Aug 2014 15:49:19 GMT]]></title><description><![CDATA[<p>Man könnte mal so etwas probieren (habs nicht gross getestet, ist nur so hingeklatscht, um die Idee zu geben):</p>
<pre><code>template &lt;typename Iter&gt;
double mean(Iter first, Iter last)
{
    auto accumulator = [](std::pair&lt;double,size_t&gt; p, double val) { p.first += val; ++p.second; return p; };
    auto acc_pair = std::accumulate(first, last, std::make_pair(0.0, 0), accumulator);
    return acc_pair.first / acc_pair.second;
}
</code></pre>
<p>Bringt aber auch einen Overhead mit, den man wahrscheidlich vermeiden möchte.</p>
<p>Bin mir auch nicht ganz sicher ob das wirklich funktioniert mit den Optimierungen, die <code>std::accumulate</code> verwendet. Wenns falsch ist wirds bestimmt gleich gesagt <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>
]]></description><link>https://www.c-plusplus.net/forum/post/2412129</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2412129</guid><dc:creator><![CDATA[icarus2]]></dc:creator><pubDate>Tue, 05 Aug 2014 15:49:19 GMT</pubDate></item><item><title><![CDATA[Reply to std::distance und size() on Tue, 05 Aug 2014 15:51:32 GMT]]></title><description><![CDATA[<p>icarus2 schrieb:</p>
<blockquote>
<p>Bringt aber auch einen Overhead mit, den man wahrscheidlich vermeiden möchte.</p>
</blockquote>
<p>Und zwar welchen Overhead ausser dem Hardcoden von double?</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2412130</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2412130</guid><dc:creator><![CDATA[overheadprojector]]></dc:creator><pubDate>Tue, 05 Aug 2014 15:51:32 GMT</pubDate></item><item><title><![CDATA[Reply to std::distance und size() on Tue, 05 Aug 2014 16:02:54 GMT]]></title><description><![CDATA[<p>volkard schrieb:</p>
<blockquote>
<p>Ha??</p>
</blockquote>
<p>Naja, das war doch der Konsens des Threads oder? Zumindest hatte ich das so verstanden:</p>
<p>SeppJ schrieb:</p>
<blockquote>
<p>Wenn du nun sagst, dass dein Iterator mehr kann, dann merkt das accumulate das und wählt eine entsprechend raffiniertere Implementierung, die dies ausnutzt. Wenn dein Iterator dann aber deine Versprechen nicht halten kann, kommt es zum beobachteten Fehler.</p>
</blockquote>
<p>Also irgendeinen Grund muss es ja geben dass std::accumulate den operator&lt; braucht und damit von dieser <a href="http://www.cplusplus.com/reference/numeric/accumulate/" rel="nofollow">Referenz-Implementierung</a> dahingehend abweicht.</p>
<p>Das mit dem lambda werd ich mal austesten, bin ich nicht selbst drauf gekommen^^</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2412132</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2412132</guid><dc:creator><![CDATA[happystudent]]></dc:creator><pubDate>Tue, 05 Aug 2014 16:02:54 GMT</pubDate></item><item><title><![CDATA[Reply to std::distance und size() on Tue, 05 Aug 2014 16:05:34 GMT]]></title><description><![CDATA[<p>volkard schrieb:</p>
<blockquote>
<p>Kellerautomat schrieb:</p>
<blockquote>
<p>lamda</p>
</blockquote>
<p>Keine gute Idee, falls accumulate unerschließliche Optimierungen machen darf.</p>
</blockquote>
<p>Darf es nicht (mehr):</p>
<p>§26.7.2 Accumulate schrieb:</p>
<blockquote>
<p>Effects:<br />
Computes its result by initializing the accumulator acc<br />
with the initial value init and then modifies it with acc = acc + *i or acc = binary_op(acc, *i) <strong>for every iterator i in the range [first,last) in order</strong>.</p>
</blockquote>
]]></description><link>https://www.c-plusplus.net/forum/post/2412133</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2412133</guid><dc:creator><![CDATA[Nathan]]></dc:creator><pubDate>Tue, 05 Aug 2014 16:05:34 GMT</pubDate></item><item><title><![CDATA[Reply to std::distance und size() on Tue, 05 Aug 2014 17:14:35 GMT]]></title><description><![CDATA[<p>Nathan schrieb:</p>
<blockquote>
<p>Darf es nicht (mehr):</p>
</blockquote>
<p>Ok, also auf gut deutsch es würde eh keinen Unterschied machen ob std::accumulate oder selbstgebaute Schleife? Weil dann könnte man sich den Stress ja eh sparen^^</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2412137</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2412137</guid><dc:creator><![CDATA[happystudent]]></dc:creator><pubDate>Tue, 05 Aug 2014 17:14:35 GMT</pubDate></item></channel></rss>