<?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[Schweres Objekt in Map einfügen]]></title><description><![CDATA[<p>Ich habe eine Ressourcenklasse <code>HeavyObject</code> , die selbst keine C++11-Movesemantik unterstützt. Nun muss ich sie in eine Map einfügen. Dabei will ich sie natürlich nicht kopieren, nachdem sie geladen wurde. Welchen Weg würdet ihr bevorzugen?</p>
<p>Ansatz 1: Erst einfügen, dann laden (komplizierteres Rollback)</p>
<pre><code>std::map&lt;ID, HeavyObject&gt; map;

auto pair = map.insert(std::make_pair(id, HeavyObject()));
if (!pair.first-&gt;load())
{
    map.erase(pair.first);
    throw std::runtime_error(&quot;load failed&quot;);
}
</code></pre>
<p>Ansatz 2: Erst in Smart-Pointer laden, dann einfügen (zusätzliche Indirektion)</p>
<pre><code>std::map&lt;ID, std::unique_ptr&lt;HeavyObject&gt;&gt; map;

std::unique_ptr&lt;HeavyObject&gt; h(new HeavyObject);
if (!h-&gt;load())
    throw std::runtime_error(&quot;load failed&quot;);

map.insert(std::make_pair(id, std::move(h)));
</code></pre>
<p>&lt;:xmas2:&gt;</p>
]]></description><link>https://www.c-plusplus.net/forum/topic/312149/schweres-objekt-in-map-einfügen</link><generator>RSS for Node</generator><lastBuildDate>Mon, 03 Aug 2026 18:46:43 GMT</lastBuildDate><atom:link href="https://www.c-plusplus.net/forum/topic/312149.rss" rel="self" type="application/rss+xml"/><pubDate>Wed, 26 Dec 2012 15:42:31 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to Schweres Objekt in Map einfügen on Wed, 26 Dec 2012 15:42:31 GMT]]></title><description><![CDATA[<p>Ich habe eine Ressourcenklasse <code>HeavyObject</code> , die selbst keine C++11-Movesemantik unterstützt. Nun muss ich sie in eine Map einfügen. Dabei will ich sie natürlich nicht kopieren, nachdem sie geladen wurde. Welchen Weg würdet ihr bevorzugen?</p>
<p>Ansatz 1: Erst einfügen, dann laden (komplizierteres Rollback)</p>
<pre><code>std::map&lt;ID, HeavyObject&gt; map;

auto pair = map.insert(std::make_pair(id, HeavyObject()));
if (!pair.first-&gt;load())
{
    map.erase(pair.first);
    throw std::runtime_error(&quot;load failed&quot;);
}
</code></pre>
<p>Ansatz 2: Erst in Smart-Pointer laden, dann einfügen (zusätzliche Indirektion)</p>
<pre><code>std::map&lt;ID, std::unique_ptr&lt;HeavyObject&gt;&gt; map;

std::unique_ptr&lt;HeavyObject&gt; h(new HeavyObject);
if (!h-&gt;load())
    throw std::runtime_error(&quot;load failed&quot;);

map.insert(std::make_pair(id, std::move(h)));
</code></pre>
<p>&lt;:xmas2:&gt;</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2283354</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2283354</guid><dc:creator><![CDATA[glühnase]]></dc:creator><pubDate>Wed, 26 Dec 2012 15:42:31 GMT</pubDate></item><item><title><![CDATA[Reply to Schweres Objekt in Map einfügen on Wed, 26 Dec 2012 15:50:15 GMT]]></title><description><![CDATA[<p>Hast du irgendwelche merkbaren Performance Probleme oder machst du es nur kompliziert weil du es meinst?</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2283357</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2283357</guid><dc:creator><![CDATA[diefrage]]></dc:creator><pubDate>Wed, 26 Dec 2012 15:50:15 GMT</pubDate></item><item><title><![CDATA[Reply to Schweres Objekt in Map einfügen on Wed, 26 Dec 2012 15:55:53 GMT]]></title><description><![CDATA[<p>Ansatz 3, der auf Ansatz 2 aufbaut:</p>
<pre><code>boost::ptr_map&lt;ID, HeavyObject&gt; map;

std::unique_ptr&lt;HeavyObject&gt; h(new HeavyObject);
if ( !h-&gt;load() )
    throw std::runtime_error(&quot;load failed&quot;);

map.insert( id, h.release() );
</code></pre>
]]></description><link>https://www.c-plusplus.net/forum/post/2283358</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2283358</guid><dc:creator><![CDATA[Sone]]></dc:creator><pubDate>Wed, 26 Dec 2012 15:55:53 GMT</pubDate></item><item><title><![CDATA[Reply to Schweres Objekt in Map einfügen on Wed, 26 Dec 2012 15:56:14 GMT]]></title><description><![CDATA[<p>Von wieviel Kilogramm sprechen wir hier?</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2283359</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2283359</guid><dc:creator><![CDATA[putter]]></dc:creator><pubDate>Wed, 26 Dec 2012 15:56:14 GMT</pubDate></item><item><title><![CDATA[Reply to Schweres Objekt in Map einfügen on Wed, 26 Dec 2012 15:57:10 GMT]]></title><description><![CDATA[<p>mit emplace / emplace_hint (und einem geeigneten Construktor von HeavyObject).</p>
<pre><code class="language-cpp">std::map&lt;ID, HeavyObject&gt; map;

auto pair_ = map.emplace(id, arg); // Mit Heavy-ObjectConstruktor, der ein Argument arg entgegen nimmt, sonst
auot pair_ = map.emplace(std::piecewise_construct, std::make_tuple(id), std::make_tuple(args...)); // mit mehr/0 Argumenten.
</code></pre>
]]></description><link>https://www.c-plusplus.net/forum/post/2283360</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2283360</guid><dc:creator><![CDATA[camper]]></dc:creator><pubDate>Wed, 26 Dec 2012 15:57:10 GMT</pubDate></item><item><title><![CDATA[Reply to Schweres Objekt in Map einfügen on Wed, 26 Dec 2012 16:08:09 GMT]]></title><description><![CDATA[<p>Übrigens wird im Ansatz 1 sogar öfter kopiert:</p>
<pre><code>auto pair = map.insert(std::make_pair(id, HeavyObject())); /// Zeile 3
</code></pre>
<p>Und Ideone gibt mir vier: <a href="http://ideone.com/OVU5lu" rel="nofollow">http://ideone.com/OVU5lu</a></p>
]]></description><link>https://www.c-plusplus.net/forum/post/2283362</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2283362</guid><dc:creator><![CDATA[Sone]]></dc:creator><pubDate>Wed, 26 Dec 2012 16:08:09 GMT</pubDate></item><item><title><![CDATA[Reply to Schweres Objekt in Map einfügen on Wed, 26 Dec 2012 16:32:47 GMT]]></title><description><![CDATA[<p>camper, vielen Dank, emplace() muss ich mir wirklich merken. Leider gibts hier keinen vernünftigen Konstruktor, d.h. ich müsste nach emplace() wieder Ansatz 1 betreiben.</p>
<p>Ausserdem kommt man bei std::map nicht darum herum, jeweils ein std::pair zu übergeben... Gerade mit C++11 hätte ich mir erhofft, dass es für insert() eine schönere Schnittstelle gäbe. Gibts einen speziellen Grund, wieso man nicht 2 Parameter für key und value haben kann? Jetzt mit Move-Semantik sollte doch Exceptionsicherheit besser in den Griff zu kriegen sein...</p>
<p>Sone, ich kann hier kein Boost verwenden, und defaultkonstruierte Objekte sind billig zu kopieren.</p>
<p>&lt;:xmas2:&gt;</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2283366</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2283366</guid><dc:creator><![CDATA[glühnase]]></dc:creator><pubDate>Wed, 26 Dec 2012 16:32:47 GMT</pubDate></item><item><title><![CDATA[Reply to Schweres Objekt in Map einfügen on Wed, 26 Dec 2012 16:49:29 GMT]]></title><description><![CDATA[<p>Sone schrieb:</p>
<blockquote>
<p>Übrigens wird im Ansatz 1 sogar öfter kopiert:</p>
<pre><code>auto pair = map.insert(std::make_pair(id, HeavyObject())); /// Zeile 3
</code></pre>
<p>Und Ideone gibt mir vier: <a href="http://ideone.com/OVU5lu" rel="nofollow">http://ideone.com/OVU5lu</a></p>
</blockquote>
<p>Das ist wahrscheinlich ein Bug der Standardbibkliothek, kann ich jedenfalls nur mit g++ 4.5 und std=c++0x reproduzieren (theoretisch sind nat. 4 Kopien möglich - davon ist die beim return in make_pair aber trivial zu vermeiden).<br />
In C++03 sollten es immer genau 3 Kopien sein.<br />
Ab g++ 4.7 sind es nur noch die erwarteten 2 Kopien (dank des Template-pair-inserts).</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2283369</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2283369</guid><dc:creator><![CDATA[camper]]></dc:creator><pubDate>Wed, 26 Dec 2012 16:49:29 GMT</pubDate></item><item><title><![CDATA[Reply to Schweres Objekt in Map einfügen on Wed, 26 Dec 2012 16:55:42 GMT]]></title><description><![CDATA[<p>glühnase schrieb:</p>
<blockquote>
<p>camper, vielen Dank, emplace() muss ich mir wirklich merken. Leider gibts hier keinen vernünftigen Konstruktor, d.h. ich müsste nach emplace() wieder Ansatz 1 betreiben.</p>
<p>Ausserdem kommt man bei std::map nicht darum herum, jeweils ein std::pair zu übergeben... Gerade mit C++11 hätte ich mir erhofft, dass es für insert() eine schönere Schnittstelle gäbe. Gibts einen speziellen Grund, wieso man nicht 2 Parameter für key und value haben kann? Jetzt mit Move-Semantik sollte doch Exceptionsicherheit besser in den Griff zu kriegen sein...</p>
</blockquote>
<p>Die schönere Schnittstelle ist emplace (und die nimmt deine zwei Argumente an)...</p>
<pre><code class="language-cpp">map.emplace(id, HeavyObject());
</code></pre>
<p>Das zugrundeliegende Problem ist hier die 2-Stufen-Konstruktion des Objektes... sofern du HeavyObject nicht verändern kannst besteht natürlich immer noch die Möglichkeit, dieses in einem Wrapper zu verpacken, der den Aufruf von Load gleich bei der Konstruktion vornimmt.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2283371</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2283371</guid><dc:creator><![CDATA[camper]]></dc:creator><pubDate>Wed, 26 Dec 2012 16:55:42 GMT</pubDate></item><item><title><![CDATA[Reply to Schweres Objekt in Map einfügen on Wed, 26 Dec 2012 17:34:36 GMT]]></title><description><![CDATA[<p>Ah, das ginge sogar, sehr schön.<br />
Leider implementiert VC++10 nur map::emplace() mit einem Parameter.</p>
<p>Vielen Dank nochmals und schöne restliche Festtage.</p>
<p>&lt;:xmas2:&gt;</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2283385</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2283385</guid><dc:creator><![CDATA[glühnase]]></dc:creator><pubDate>Wed, 26 Dec 2012 17:34:36 GMT</pubDate></item><item><title><![CDATA[Reply to Schweres Objekt in Map einfügen on Wed, 26 Dec 2012 18:12:30 GMT]]></title><description><![CDATA[<p>camper schrieb:</p>
<blockquote>
<p>Sone schrieb:</p>
<blockquote>
<p>Übrigens wird im Ansatz 1 sogar öfter kopiert:</p>
<pre><code>auto pair = map.insert(std::make_pair(id, HeavyObject())); /// Zeile 3
</code></pre>
<p>Und Ideone gibt mir vier: <a href="http://ideone.com/OVU5lu" rel="nofollow">http://ideone.com/OVU5lu</a></p>
</blockquote>
<p>Das ist wahrscheinlich ein Bug der Standardbibkliothek, kann ich jedenfalls nur mit g++ 4.5 und std=c++0x reproduzieren (theoretisch sind nat. 4 Kopien möglich - davon ist die beim return in make_pair aber trivial zu vermeiden).<br />
In C++03 sollten es immer genau 3 Kopien sein.<br />
Ab g++ 4.7 sind es nur noch die erwarteten 2 Kopien (dank des Template-pair-inserts).</p>
</blockquote>
<p>Nach ein bisschen Experimentieren stelle ich fest, das der Fehler offenbar doch woanders liegt:<br />
Weder g++ 4.5 noch g++ 4.6 führen bei std::pair im c++0x normale RVO durch (jedenfalls nicht mit so einem Membertyp), was beim Aufruf von make_pair 2 zusätzliche Kopien erzeugt. Bei g++ 4.6 fällt das nicht so auf, weil dort dafür dank des template-inserts beim insert nur noch eine Kopie entsteht.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2283403</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2283403</guid><dc:creator><![CDATA[camper]]></dc:creator><pubDate>Wed, 26 Dec 2012 18:12:30 GMT</pubDate></item><item><title><![CDATA[Reply to Schweres Objekt in Map einfügen on Wed, 26 Dec 2012 18:43:15 GMT]]></title><description><![CDATA[<p>1. Kopie: Funktionsparameter von make_pair wird mit der Temporary initialisiert<br />
2. Kopie: Das <code>HeavyObject</code> im zurückgegebenen <code>pair</code> wird mit dem Funktionsparameter initialisiert.<br />
3. Kopie: Das HeavyObject im Funktionsparameter vom insert wird mit dem HeavyObject aus dem Rückgabewert von make_pair initialisiert.<br />
4. Kopie: <code>insert</code> wird für den internen Baum den Funktionsparameter, das <code>pair</code> , erneut kopieren.</p>
<p>Soweit richtig?</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2283420</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2283420</guid><dc:creator><![CDATA[Sone]]></dc:creator><pubDate>Wed, 26 Dec 2012 18:43:15 GMT</pubDate></item><item><title><![CDATA[Reply to Schweres Objekt in Map einfügen on Wed, 26 Dec 2012 20:08:58 GMT]]></title><description><![CDATA[<p>Sone schrieb:</p>
<blockquote>
<p>1. Kopie: Funktionsparameter von make_pair wird mit der Temporary initialisiert<br />
2. Kopie: Das <code>HeavyObject</code> im zurückgegebenen <code>pair</code> wird mit dem Funktionsparameter initialisiert.<br />
3. Kopie: Das HeavyObject im Funktionsparameter vom insert wird mit dem HeavyObject aus dem Rückgabewert von make_pair initialisiert.<br />
4. Kopie: <code>insert</code> wird für den internen Baum den Funktionsparameter, das <code>pair</code> , erneut kopieren.</p>
<p>Soweit richtig?</p>
</blockquote>
<p>Make_pair hat Referenzparameter, dort entsteht keine Kopie. g++ vor 4.6 führt innerhalb von insert 2 Kopien durch, warum auch immer.<br />
Nach ein bisschen mehr Experimentieren habe ich das Problem reduzieren können:</p>
<pre><code class="language-cpp">#include &lt;iostream&gt;
#include &lt;type_traits&gt;

template &lt;typename T&gt;
struct foo
{
    typedef T first_type;
    T value;

    foo(const foo&amp;) = default;
    foo(foo&amp;&amp;) = default;

    foo() : value() {}

    foo(const T&amp; x) : value(x) {}

    template&lt;class U&gt;
    foo(U&amp;&amp; x) : value(std::forward&lt;U&gt;(x)) {}

    template&lt;class U,
        typename std::enable_if&lt;std::is_convertible&lt;U,T&gt;::value, int&gt;::type = 0&gt;
    foo(foo&lt;U&gt;&amp;&amp; p) : value(std::forward&lt;U&gt;(p.value))
    {
        std::cout &lt;&lt; &quot;Template-foo-move\n&quot;;
    }

};

template &lt;typename T&gt;
foo&lt;typename std::decay&lt;T&gt;::type&gt;
make_foo(T&amp;&amp; t)
{
    return foo&lt;typename std::decay&lt;T&gt;::type&gt;(std::forward&lt;T&gt;(t));
}

struct bar
{
    bar() = default;
    bar(const bar&amp;) { std::cout &lt;&lt; &quot;Copy-ctor!\n&quot;; }
};

int main()
{
    auto x = make_foo((bar()));
}
</code></pre>
<p>Ausgabe mit g++4.7.2 oder 4.8 oder clang:</p>
<pre><code>Copy-ctor!
</code></pre>
<p>In g++ vor 4.7 muss aber die defaulted-Definiton des Move-Konstruktors weg (führt zum Fehler). Implizit wird dieser Move-Konstruktor aber nicht deklariert, und das macht dann plötzlich den Templatekonstruktor zu einer passenden Wahl, wenn foo gemoved werden sollte. Weil das aber kein Move-Konstruktor ist, kann er auch nicht eliminiert werden.<br />
Ausgabe ohne defaulted-Move:</p>
<pre><code class="language-cpp">Copy-ctor!
Copy-ctor!
Template-foo-move
Copy-ctor!
Template-foo-move
</code></pre>
<p>/usr/lib64/gcc/x86_64-pc-linux-gnu/4.6.3/include/g++-v4/bits/stl_pair.h schrieb:</p>
<blockquote>
<pre><code class="language-cpp">#ifdef __GXX_EXPERIMENTAL_CXX0X__
      constexpr pair(const pair&amp;) = default;

      // Implicit.
      // pair(pair&amp;&amp;) = default;
</code></pre>
</blockquote>
<p>Dieser Kommentar ist offensichtlich falsch. Wenn ich mit g++ 4.5 oder 4.6 den rvalue-pair-Templatekonstruktor entferne, wird der Copy-Konstruktor ausgewählt und der kann dann eliminiert werden.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2283442</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2283442</guid><dc:creator><![CDATA[camper]]></dc:creator><pubDate>Wed, 26 Dec 2012 20:08:58 GMT</pubDate></item><item><title><![CDATA[Reply to Schweres Objekt in Map einfügen on Wed, 26 Dec 2012 20:25:30 GMT]]></title><description><![CDATA[<p>:augen glänzen:<br />
Eine letzte Frage hätte ich noch:</p>
<blockquote>
<p>g++ vor 4.6 führt innerhalb von insert 2 Kopien durch, warum auch immer.</p>
</blockquote>
<p>Darf er das überhaupt?</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2283449</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2283449</guid><dc:creator><![CDATA[sone_logoff]]></dc:creator><pubDate>Wed, 26 Dec 2012 20:25:30 GMT</pubDate></item><item><title><![CDATA[Reply to Schweres Objekt in Map einfügen on Wed, 26 Dec 2012 20:30:10 GMT]]></title><description><![CDATA[<p>Hier noch mal der Standard gegen das was im oben zitierten Kommentar steht:</p>
<p>N3337 §12.8 / 9 schrieb:</p>
<blockquote>
<p>If the deﬁnition of a class X does not explicitly declare a move constructor, one will be implicitly declared as defaulted if and only if<br />
— X does not have a user-declared copy constructor,</p>
</blockquote>
]]></description><link>https://www.c-plusplus.net/forum/post/2283452</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2283452</guid><dc:creator><![CDATA[sone_logoff]]></dc:creator><pubDate>Wed, 26 Dec 2012 20:30:10 GMT</pubDate></item><item><title><![CDATA[Reply to Schweres Objekt in Map einfügen on Wed, 26 Dec 2012 20:37:11 GMT]]></title><description><![CDATA[<p>sone_logoff schrieb:</p>
<blockquote>
<p>:augen glänzen:<br />
Eine letzte Frage hätte ich noch:</p>
<blockquote>
<p>g++ vor 4.6 führt innerhalb von insert 2 Kopien durch, warum auch immer.</p>
</blockquote>
<p>Darf er das überhaupt?</p>
</blockquote>
<p>Zitat habe ich keines und auch keine Lust zu suchen. Zumindest in C++03 scheint mir das ein reines QoI-Problem zu sein, also denke ich mal, dass es zumindest dort erlaubt ist.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2283453</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2283453</guid><dc:creator><![CDATA[camper]]></dc:creator><pubDate>Wed, 26 Dec 2012 20:37:11 GMT</pubDate></item><item><title><![CDATA[Reply to Schweres Objekt in Map einfügen on Thu, 27 Dec 2012 09:30:53 GMT]]></title><description><![CDATA[<p>Mir ist da noch etwas aufgefallen. Ich wollte es eigentlich mit dem unique_ptr lösen (Ansatz 2).</p>
<p>Allerdings ist das relativ ungünstig, falls die ID schon in der Map gespeichert ist. Dann wird das HeavyObject trotzdem geladen, obwohl es nachher nicht eingefügt werden kann. Wahrscheinlich kommt so ein Fehler zwar nicht häufig vor, aber würdet ihr den noch separat checken?</p>
<p>&lt;:xmas2:&gt;</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2283544</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2283544</guid><dc:creator><![CDATA[glühnase]]></dc:creator><pubDate>Thu, 27 Dec 2012 09:30:53 GMT</pubDate></item><item><title><![CDATA[Reply to Schweres Objekt in Map einfügen on Fri, 28 Dec 2012 02:26:54 GMT]]></title><description><![CDATA[<p>Ja, klar, prüf vorher ob es den Key schon gibt.<br />
Ist ja kein echter Aufwand.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2283787</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2283787</guid><dc:creator><![CDATA[hustbaer]]></dc:creator><pubDate>Fri, 28 Dec 2012 02:26:54 GMT</pubDate></item></channel></rss>