<?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[boost::ptr_vector mit unkopierbaren Objekten]]></title><description><![CDATA[<p>Hi,</p>
<p>ich habe eine Klasse, die nicht kopierbar ist. Allokierte Instanzen will ich in einen <code>boost::ptr_vector</code> stecken, wobei ich aber den Fehler bekomme, dass die Objekte darin nicht geklont werden können:</p>
<pre><code class="language-cpp">#include &lt;boost/ptr_container/ptr_vector.hpp&gt;

class foo {
	public:
		foo() {}
	private:
		foo( const foo&amp; );
		foo&amp; operator=( const foo&amp; );
};

boost::ptr_vector&lt;foo&gt; bar() {
	boost::ptr_vector&lt;foo&gt; Arr;
	Arr.push_back( new foo() );
	return Arr;
}

int main() {
	boost::ptr_vector&lt;foo&gt; X = bar();
}
</code></pre>
<p>Mir ist mittlerweile immerhin klar, <em>warum</em> die Objekte geklont werden sollen. Als Abhilfe könnte ich der Funktion <code>bar</code> auch eine Referenz auf den <code>ptr_vector</code> mitgeben und ihn da füllen lassen - ich bin aber grad etwas bockig und sehe nicht ein irgendwas umzubauen nur damit boost zufrieden ist.</p>
<p>Hat jemand einen anderen Workaround oder eine Idee, einen Alternativcontainer oder Sonstiges? An sich müssen ja nur die Zeiger umkopiert werden, das kann ja nicht so schwer sein; und der Container sollte halt Ownership der Objekte haben.</p>
]]></description><link>https://www.c-plusplus.net/forum/topic/278463/boost-ptr_vector-mit-unkopierbaren-objekten</link><generator>RSS for Node</generator><lastBuildDate>Tue, 25 Aug 2026 05:14:38 GMT</lastBuildDate><atom:link href="https://www.c-plusplus.net/forum/topic/278463.rss" rel="self" type="application/rss+xml"/><pubDate>Tue, 07 Dec 2010 11:58:50 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to boost::ptr_vector mit unkopierbaren Objekten on Tue, 07 Dec 2010 11:58:50 GMT]]></title><description><![CDATA[<p>Hi,</p>
<p>ich habe eine Klasse, die nicht kopierbar ist. Allokierte Instanzen will ich in einen <code>boost::ptr_vector</code> stecken, wobei ich aber den Fehler bekomme, dass die Objekte darin nicht geklont werden können:</p>
<pre><code class="language-cpp">#include &lt;boost/ptr_container/ptr_vector.hpp&gt;

class foo {
	public:
		foo() {}
	private:
		foo( const foo&amp; );
		foo&amp; operator=( const foo&amp; );
};

boost::ptr_vector&lt;foo&gt; bar() {
	boost::ptr_vector&lt;foo&gt; Arr;
	Arr.push_back( new foo() );
	return Arr;
}

int main() {
	boost::ptr_vector&lt;foo&gt; X = bar();
}
</code></pre>
<p>Mir ist mittlerweile immerhin klar, <em>warum</em> die Objekte geklont werden sollen. Als Abhilfe könnte ich der Funktion <code>bar</code> auch eine Referenz auf den <code>ptr_vector</code> mitgeben und ihn da füllen lassen - ich bin aber grad etwas bockig und sehe nicht ein irgendwas umzubauen nur damit boost zufrieden ist.</p>
<p>Hat jemand einen anderen Workaround oder eine Idee, einen Alternativcontainer oder Sonstiges? An sich müssen ja nur die Zeiger umkopiert werden, das kann ja nicht so schwer sein; und der Container sollte halt Ownership der Objekte haben.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1990944</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1990944</guid><dc:creator><![CDATA[asdasdasd]]></dc:creator><pubDate>Tue, 07 Dec 2010 11:58:50 GMT</pubDate></item><item><title><![CDATA[Reply to boost::ptr_vector mit unkopierbaren Objekten on Tue, 07 Dec 2010 12:07:06 GMT]]></title><description><![CDATA[<p>Ok, mir ist grad <code>std::vector&lt;std::auto_ptr&lt;foo&gt; &gt;</code> eingefallen, oder verträgt sich das nicht? Zumindest beim Zurückgeben scheint's zu klappen, kopieren kann man den Container dann natürlich nicht, aber einen <code>std::vector&lt;boost::shared_ptr&lt;foo&gt; &gt;</code> will ich echt nicht einsetzen.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1990952</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1990952</guid><dc:creator><![CDATA[asdasdasd]]></dc:creator><pubDate>Tue, 07 Dec 2010 12:07:06 GMT</pubDate></item><item><title><![CDATA[Reply to boost::ptr_vector mit unkopierbaren Objekten on Tue, 07 Dec 2010 12:08:09 GMT]]></title><description><![CDATA[<p>asdasdasd schrieb:</p>
<blockquote>
<p>kopieren kann man den Container dann natürlich nicht</p>
</blockquote>
<p>Ich meine natürlich: Man kann dann keine zwei Container-Instanzen mit den gleichen Zeigern gleichzeitig halten.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1990955</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1990955</guid><dc:creator><![CDATA[asdasdasd]]></dc:creator><pubDate>Tue, 07 Dec 2010 12:08:09 GMT</pubDate></item><item><title><![CDATA[Reply to boost::ptr_vector mit unkopierbaren Objekten on Tue, 07 Dec 2010 12:09:01 GMT]]></title><description><![CDATA[<p>Container und auto_ptr vertragen sich nicht. Nimm shared_ptr aus TR1 oder boost.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1990957</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1990957</guid><dc:creator><![CDATA[DocShoe]]></dc:creator><pubDate>Tue, 07 Dec 2010 12:09:01 GMT</pubDate></item><item><title><![CDATA[Reply to boost::ptr_vector mit unkopierbaren Objekten on Tue, 07 Dec 2010 13:45:00 GMT]]></title><description><![CDATA[<p>Du könntest (solange das von boost nicht implementiert wird) den ptr_vector in einer Klasse wrappen, die einen move ctor hat. In dem kannst du ptr_vector::swap verwenden.<br />
Alternativ kannst du, wenn du keinen vector&lt;shared_ptr&lt;T&gt; &gt; verwenden möchtest, einen vector&lt;unique_ptr&lt;T&gt; &gt; benutzen. Da solltest du aber vorher prüfen ob das in dein System passt, denn mit dem unique_ptr kannst du nicht alles machen wie mit einem shared_ptr.<br />
Beide Lösungen verlangen nach einem neuen Compiler, der das auch kann.</p>
<p>Bei der Variante mit Übergabe des Containers als Referenz würde ich ansonsten nach Möglichkeit eher etwas tun wie</p>
<pre><code class="language-cpp">template&lt;typename OutIter&gt;
void bar(OutIter out)
{
    for(int i = 0; i &lt; 5; ++i, ++out)
        *out = new foo();
}

int main()
{
    boost::ptr_vector&lt;foo&gt; v;
    bar(std::back_inserter(v));
    return 0;
}
</code></pre>
]]></description><link>https://www.c-plusplus.net/forum/post/1991034</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1991034</guid><dc:creator><![CDATA[brotbernd]]></dc:creator><pubDate>Tue, 07 Dec 2010 13:45:00 GMT</pubDate></item><item><title><![CDATA[Reply to boost::ptr_vector mit unkopierbaren Objekten on Tue, 07 Dec 2010 16:33:23 GMT]]></title><description><![CDATA[<p>oki doki, danke</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1991140</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1991140</guid><dc:creator><![CDATA[asdasdasd]]></dc:creator><pubDate>Tue, 07 Dec 2010 16:33:23 GMT</pubDate></item><item><title><![CDATA[Reply to boost::ptr_vector mit unkopierbaren Objekten on Tue, 07 Dec 2010 18:01:42 GMT]]></title><description><![CDATA[<p>Zwei weitere C++98-Möglichkeiten, die mir spontan einfallen:</p>
<pre><code class="language-cpp">void bar(boost::ptr_vector&lt;foo&gt;&amp; out);
// Vorteil: Keine Anforderungen an Speicherklasse von out
// Nachteil: Kein Rückgabewert, daher nicht in temporären Ausdrücken einsetzbar

std::auto_ptr&lt; boost::ptr_vector&lt;foo&gt; &gt; bar();
// Vorteil: Move-Semantik mit C++98
// Nachteil: Container muss dynamisch angefordert werden
</code></pre>
<p>Wenn du C++0x verwendest, brauchst du gar keine Wrapperklasse, sondern kannst direkt den Container verschieben:</p>
<pre><code class="language-cpp">boost::ptr_vector&lt;foo&gt;&amp;&amp; bar();
</code></pre>
]]></description><link>https://www.c-plusplus.net/forum/post/1991171</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1991171</guid><dc:creator><![CDATA[Nexus]]></dc:creator><pubDate>Tue, 07 Dec 2010 18:01:42 GMT</pubDate></item><item><title><![CDATA[Reply to boost::ptr_vector mit unkopierbaren Objekten on Tue, 07 Dec 2010 18:18:34 GMT]]></title><description><![CDATA[<p>Nexus schrieb:</p>
<blockquote>
<p>Wenn du C++0x verwendest, brauchst du gar keine Wrapperklasse, sondern kannst direkt den Container verschieben:</p>
<pre><code class="language-cpp">boost::ptr_vector&lt;foo&gt;&amp;&amp; bar();
</code></pre>
</blockquote>
<p>Ääh, zeig mal bitte. Muss ich nochmal nachsitzen... <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/1991186</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1991186</guid><dc:creator><![CDATA[brotbernd]]></dc:creator><pubDate>Tue, 07 Dec 2010 18:18:34 GMT</pubDate></item><item><title><![CDATA[Reply to boost::ptr_vector mit unkopierbaren Objekten on Tue, 07 Dec 2010 20:03:29 GMT]]></title><description><![CDATA[<p>brotbernd schrieb:</p>
<blockquote>
<p>Ääh, zeig mal bitte. Muss ich nochmal nachsitzen... <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>
</blockquote>
<p>Ich hätte mir das so vorgestellt, muss aber anmerken, dass ich mich noch nicht sehr gut mit RValue-Referenzen auskenne. Um den Code von asdasdasd zu nehmen:</p>
<pre><code class="language-cpp">boost::ptr_vector&lt;foo&gt;&amp;&amp; bar()
{
    boost::ptr_vector&lt;foo&gt; Arr;
    Arr.push_back( new foo() );
    return std::move(Arr);
}
</code></pre>
]]></description><link>https://www.c-plusplus.net/forum/post/1991232</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1991232</guid><dc:creator><![CDATA[Nexus]]></dc:creator><pubDate>Tue, 07 Dec 2010 20:03:29 GMT</pubDate></item><item><title><![CDATA[Reply to boost::ptr_vector mit unkopierbaren Objekten on Wed, 08 Dec 2010 07:16:49 GMT]]></title><description><![CDATA[<p>Ich bin da auch noch nicht so ganz sicher mit dem Kram, aber in meinem bisherigen Verständnis dachte ich, das Ziel bräuchte einen Ctor <code>ptr_vector(ptr_vector&amp;&amp;)</code> , der die rvalue Referenz annimmt und ihr den Inhalt klaut.<br />
Dein Code ruft bei mir zumindest wieder den copy ctor auf und verlangt nach einem clone, wohingegen das hier funktioniert:</p>
<pre><code class="language-cpp">struct Wrap
{
    Wrap(){}
    Wrap(Wrap&amp;&amp; r)
    {
        v.swap(r.v);
    }
    boost::ptr_vector&lt;foo&gt; v;
private:
    Wrap(Wrap&amp;);
    void operator=(Wrap&amp;);
};

Wrap baz()
{
    Wrap w;
    w.v.push_back( new foo() );
    return w;
}
</code></pre>
]]></description><link>https://www.c-plusplus.net/forum/post/1991324</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1991324</guid><dc:creator><![CDATA[brotbernd]]></dc:creator><pubDate>Wed, 08 Dec 2010 07:16:49 GMT</pubDate></item><item><title><![CDATA[Reply to boost::ptr_vector mit unkopierbaren Objekten on Wed, 08 Dec 2010 08:42:32 GMT]]></title><description><![CDATA[<p>brotbernd schrieb:</p>
<blockquote>
<p>Ich bin da auch noch nicht so ganz sicher mit dem Kram, aber in meinem bisherigen Verständnis dachte ich, das Ziel bräuchte einen Ctor <code>ptr_vector(ptr_vector&amp;&amp;)</code> , der die rvalue Referenz annimmt und ihr den Inhalt klaut.<br />
Dein Code ruft bei mir zumindest wieder den copy ctor auf und verlangt nach einem clone, wohingegen das hier funktioniert:</p>
</blockquote>
<p>Ich vermute mal Nexus geht davon aus, dass der Ctor ptr_vector(ptr_vector&amp;&amp;)<br />
bereits vorhanden ist.</p>
<p>Das move macht er wahrscheinlich aus folgendem Grund:</p>
<blockquote>
<p>For safety reasons a named variable will never be considered to be an rvalue even if it's declared as such; in order to get an rvalue the function template std::move&lt;T&gt;() should be used.</p>
</blockquote>
<p><a href="http://en.wikipedia.org/wiki/C%2B%2B0x#Rvalue_reference_and_move_semantics" rel="nofollow">http://en.wikipedia.org/wiki/C%2B%2B0x#Rvalue_reference_and_move_semantics</a></p>
<p>Gruß,<br />
XSpille</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1991343</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1991343</guid><dc:creator><![CDATA[XSpille]]></dc:creator><pubDate>Wed, 08 Dec 2010 08:42:32 GMT</pubDate></item><item><title><![CDATA[Reply to boost::ptr_vector mit unkopierbaren Objekten on Wed, 08 Dec 2010 09:41:42 GMT]]></title><description><![CDATA[<p>XSpille schrieb:</p>
<blockquote>
<p>Ich vermute mal Nexus geht davon aus, dass der Ctor ptr_vector(ptr_vector&amp;&amp;)<br />
bereits vorhanden ist.</p>
</blockquote>
<p>Ich schrieb ja im ersten Post, ein Wrapper sei nötig solange der Container keinen eigenen move ctor hat. Darum wunderte ich mich, als er sagte es würde auch ohne gehen.</p>
<p>XSpille schrieb:</p>
<blockquote>
<p>Das move macht er wahrscheinlich aus folgendem Grund: ...</p>
</blockquote>
<p>Ja hm, ich weiß nicht wie das genau geregelt ist, aber beim Rückgabewert hat das bisher bei mir so funktioniert. Ich hab mich da orientiert an:</p>
<blockquote>
<p>1. If A has an accessible copy or move constructor, the compiler may choose to elide the copy<br />
2. otherwise, if A has a move constructor, v is moved<br />
3. otherwise, if A has a copy constructor, v is copied<br />
4. otherwise, a compile time error is emitted.</p>
<p>aus: <a href="http://cpp-next.com/archive/2009/09/move-it-with-rvalue-references/" rel="nofollow">http://cpp-next.com/archive/2009/09/move-it-with-rvalue-references/</a></p>
</blockquote>
]]></description><link>https://www.c-plusplus.net/forum/post/1991359</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1991359</guid><dc:creator><![CDATA[brotbernd]]></dc:creator><pubDate>Wed, 08 Dec 2010 09:41:42 GMT</pubDate></item><item><title><![CDATA[Reply to boost::ptr_vector mit unkopierbaren Objekten on Wed, 08 Dec 2010 11:10:26 GMT]]></title><description><![CDATA[<p>Nexus schrieb:</p>
<blockquote>
<p>Ich hätte mir das so vorgestellt, muss aber anmerken, dass ich mich noch nicht sehr gut mit RValue-Referenzen auskenne. Um den Code von asdasdasd zu nehmen:</p>
<pre><code class="language-cpp">boost::ptr_vector&lt;foo&gt;&amp;&amp; bar()
{
    boost::ptr_vector&lt;foo&gt; Arr;
    Arr.push_back( new foo() );
    return std::move(Arr);
}
</code></pre>
</blockquote>
<p>Ein Beispiel, wie man es <em>nicht</em> machen sollte. Du gibst hier eine Referenz auf ein lokal erzeugtes Objekt zurück. Verwendung dieser Referenz ruft undefiniertes Verhalten hervor. Setze &amp;&amp; nur ein, wenn Du genau weißt, was Du tust. Typischer Einsatzzweck von &amp;&amp; bzgl Move-Semantik ist der Move-Konstruktor einer Klasse sowie ein Move-Assignment-Operator.</p>
<p>Das, was Du machen wolltest, muss <em>so</em> aussehen:</p>
<pre><code class="language-cpp">boost::ptr_vector&lt;foo&gt; bar()
{
    boost::ptr_vector&lt;foo&gt; Arr;
    Arr.push_back( new foo() );
    return Arr;
}
</code></pre>
<p>Wie man sieht, muss man hier gar nichts besonderes machen, um Move-Semantik nutzen zu können. Es sieht nach reinem C++98 Code aus. Und das ist auch der Witz an dem neuen Sprach-Feature. Es werden automatisch einige unnötige Kopien durch Moves ersetzt. Lediglich boost::ptr_vector&lt;foo&gt; muss einen Move-Konstruktor haben. Das war's schon. Auch die Verwendung von std::move ist hier überflüssig und sogar eher schädlich, da dadurch NRVO ausgehebelt werden könnte.</p>
<p>Im Prinzip wurden die &quot;copy elision&quot;-Regeln nur erweitert. Der C++ Standard erlaubt ja in bestimmten Situationen &quot;copy elisions&quot;, also das Wegoptimieren von Kopien. Die C++0x Erweiterung sieht nun so aus, dass ein Compiler, der eine Kopie wegoptimieren <em>dürfte</em>, es aber aus irgendwelchen Gründen nicht kann, soll das Quellobjekt als Rvalue behandeln bei der Überladungsauflösung beim Kontruieren einer &quot;Kopie&quot;. Das trifft hier auch auf &quot;Arr&quot; zu. Der C++ Standard sagt, dass, weil &quot;Arr&quot; ein lokales Objekt ist, bei &quot;return Arr;&quot; die sogenannte <a href="http://en.wikipedia.org/wiki/Return_value_optimization" rel="nofollow">NRVO</a> durchgeführt werden <em>darf</em>. Ein guter Compiler wie zB der aktuelle GCC kann hier auch NRVO durchführen. Ein C++0x Compiler, der das nicht kann, muss zumindest &quot;Arr&quot; als Rvalue für das Konstruieren des Return-Wertes behandelt. Wenn also boost::ptr_container&lt;foo&gt; einen Move-Konstruktor hat, wird garantiert kein Copy-Konstruktor ausgeführt. Entweder, weil der Compiler NRVO durchführt oder einen Move-Konstruktor nehmen würde.</p>
<p>kk</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1991393</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1991393</guid><dc:creator><![CDATA[krümelkacker]]></dc:creator><pubDate>Wed, 08 Dec 2010 11:10:26 GMT</pubDate></item><item><title><![CDATA[Reply to boost::ptr_vector mit unkopierbaren Objekten on Wed, 08 Dec 2010 16:46:48 GMT]]></title><description><![CDATA[<p>krümelkacker schrieb:</p>
<blockquote>
<p>Typischer Einsatzzweck von &amp;&amp; bzgl Move-Semantik ist der Move-Konstruktor einer Klasse sowie ein Move-Assignment-Operator.</p>
</blockquote>
<p>Wann braucht man das &amp;&amp; denn noch?<br />
Braucht man das &amp;&amp; auch außerhalb der Parameter von Funktionsdeklarationen.<br />
Im Rückgabetyp ja scheinbar nicht, oder?</p>
<p>Sehe ich es richtig, dass ein Parameter mit dem &amp;&amp; immer vorgezogen wird,<br />
wenn das andere Objekt danach gelöscht wird?</p>
<p>Wird in so einem Fall</p>
<pre><code class="language-cpp">while(...){
  MyObject a;
  // MyObjectB b;
  ...
  doSomething(a);
}
</code></pre>
<p>eine Funktion mit dieser Signatur</p>
<pre><code class="language-cpp">void doSomething(MyObject&amp;&amp; o);
</code></pre>
<p>einer Funktion mit dieser Signatur</p>
<pre><code class="language-cpp">void doSomething(MyObject&amp; o);
</code></pre>
<p>vorgezogen wird?</p>
<p>Was passiert wenn die Zeile mit MyObjectB b; eingefügt wird?<br />
Wäre es dann immernoch so? Immerhin muss ja (eigentlich) der Destruktor<br />
von b vor dem von a ausgeführt werden.</p>
<p>Gruß,<br />
XSpille</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1991567</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1991567</guid><dc:creator><![CDATA[XSpille]]></dc:creator><pubDate>Wed, 08 Dec 2010 16:46:48 GMT</pubDate></item><item><title><![CDATA[Reply to boost::ptr_vector mit unkopierbaren Objekten on Wed, 08 Dec 2010 19:01:24 GMT]]></title><description><![CDATA[<p>krümelkacker schrieb:</p>
<blockquote>
<p>Ein Beispiel, wie man es <em>nicht</em> machen sollte. Du gibst hier eine Referenz auf ein lokal erzeugtes Objekt zurück. Verwendung dieser Referenz ruft undefiniertes Verhalten hervor.</p>
</blockquote>
<p>Ah, vielen Dank für die Korrektur. Das erklärt auch, wieso bei einem kurzen Test kein Move-Konstruktor aufgerufen wurde... Ich dachte zuerst, das läge an einer nicht ganz aktuellen Compiler-Implementierung von C++0x.</p>
<p>krümelkacker schrieb:</p>
<blockquote>
<p>Setze &amp;&amp; nur ein, wenn Du genau weißt, was Du tust. Typischer Einsatzzweck von &amp;&amp; bzgl Move-Semantik ist der Move-Konstruktor einer Klasse sowie ein Move-Assignment-Operator.</p>
</blockquote>
<p>Gibt es denn Fälle, in denen man eine RValue-Referenz als Rückgabetyp benutzt, abgesehen von weitergereichten Parametern?</p>
<p>krümelkacker schrieb:</p>
<blockquote>
<p>Wenn also boost::ptr_container&lt;foo&gt; einen Move-Konstruktor hat, wird garantiert kein Copy-Konstruktor ausgeführt. Entweder, weil der Compiler NRVO durchführt oder einen Move-Konstruktor nehmen würde.</p>
</blockquote>
<p>Danke für die ausführliche Erläuterung!</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1991643</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1991643</guid><dc:creator><![CDATA[Nexus]]></dc:creator><pubDate>Wed, 08 Dec 2010 19:01:24 GMT</pubDate></item><item><title><![CDATA[Reply to boost::ptr_vector mit unkopierbaren Objekten on Wed, 08 Dec 2010 20:23:24 GMT]]></title><description><![CDATA[<p>XSpille schrieb:</p>
<blockquote>
<p>Wann braucht man das &amp;&amp; denn noch?<br />
Braucht man das &amp;&amp; auch außerhalb der Parameter von Funktionsdeklarationen.<br />
Im Rückgabetyp ja scheinbar nicht, oder?</p>
</blockquote>
<p>Normalerweise nicht. Ausnahmen sind std::move und std::forward. Es gibt vielleicht noch ein paar andere. Aber als Daumenregel würde ich Dir da recht geben -- also... dass man lieber keine Funktionen schreibt, die Rvalue-Referenzen zurückgeben.</p>
<p>XSpille schrieb:</p>
<blockquote>
<p>Sehe ich es richtig, dass ein Parameter mit dem &amp;&amp; immer vorgezogen wird,<br />
wenn das andere Objekt danach gelöscht wird?</p>
</blockquote>
<p>Dir ist scheinbar das Lvalue/Rvalue-Konzept noch nicht ganz bekannt. Jeder Ausdruck gehört zu einer von drei sogenannten Werte-Kategorien (engl: &quot;value category&quot;). Es ist eine Eigenschaft eines Ausdrucks und wird zB beim Initialisieren von Referenzen und der Überladungsauflösung berücksichtigt. Wenn soweit klar ist, was es für Werte-Kategorien gibt und wann diese auftauchen, kannst Du dir die Tabelle &quot;Binding and Overloading&quot; <a href="http://cpp-next.com/archive/2009/09/move-it-with-rvalue-references/" rel="nofollow">hier</a> angucken.</p>
<p>(Sinngemäßes Zitat)</p>
<p>XSpille schrieb:</p>
<blockquote>
<p>Wird in so einem Fall</p>
<pre><code class="language-cpp">void doSomething(MyObject&amp; o);  // #1
void doSomething(MyObject&amp;&amp; o); // #2

while(...){
  MyObject a;
  //MyObject b;
  ...
  doSomething(a);
}
</code></pre>
<p>#1 oder #2 aufgerufen?</p>
</blockquote>
<p>#1, da <code>a</code> kein Rvalue-Ausdruck sondern ein Lvalue-Ausdruck ist.</p>
<p>XSpille schrieb:</p>
<blockquote>
<p>Was passiert wenn die Zeile mit MyObjectB b; eingefügt wird?<br />
Wäre es dann immernoch so? Immerhin muss ja (eigentlich) der Destruktor<br />
von b vor dem von a ausgeführt werden.</p>
</blockquote>
<p>Ja und? a ist immer noch ein Lvalue-Ausdruck und es wird immernoch #1 aufgerufen. Und der Destruktor von b wird dann immer noch vor dem Destruktor von a ausgeführt.</p>
<p>Du kannst aber explizit mit std::move sagen, dass Dir nichts mehr an a liegt:</p>
<pre><code class="language-cpp">doSomething(std::move(a));
</code></pre>
<p>Und std::move sieht in etwa so aus:</p>
<pre><code class="language-cpp">template&lt;class T&gt; T&amp;&amp; move(T&amp; x) {return static_cast&lt;T&amp;&amp;&gt;(x);}
</code></pre>
<p>Damit liefert move einen Rvalue-Ausdruck (genauer: Xvalue) und doSomething #2 wird aufgerufen. Tatsächlich &quot;bewegt&quot; sich hier gar nichts. std::move gibt einem nur eine Referenz zurück. Dies ist aber eine <em>unbenannte</em> Rvalue-Referenz und gehört daher selbst der Rvalue-Kategorie an. Beachte, dass, nachdem man eine <em>benannte</em> Rvalue-Referenz initialisiert hat, die Verwendung des Namens als Ausdruck aber selbst ein Lvalue-Ausdruck ist.</p>
<p>Rvalue-Referenzen funktionieren fast genauso wie Lvalue-Referenzen, nur dass die &quot;Binding and Overloading&quot;-Regeln etwas anders aussehen, siehe Tabelle aus der Artikelserie. Darüber hinaus gibt es noch zwei Besonderheiten. 1. Es gibt ein sogenanntes &quot;Reference-Collapsing&quot;:</p>
<pre><code>T     | T&amp;&amp;   | T&amp;        Quasi  &amp; + &amp;  = &amp;
------+-------+------            &amp; + &amp;&amp; = &amp;
int   | int&amp;&amp; | int&amp;            &amp;&amp; + &amp;  = &amp;
------+       |                 &amp;&amp; + &amp;&amp; = &amp;&amp;
int&amp;&amp; : [b]int&amp;&amp;[/b] | [b]int&amp;[/b]
--------------+
int&amp;  : [b]int&amp;[/b]  : [b]int&amp;[/b]
</code></pre>
<p>2. Es gibt eine Sonderregel bei der Template-Argument-Deduktion. Taucht irgendwo &quot;P&amp;&amp;&quot; als Funktions-Parameter auf, wobei P ein Template-Typ-Parameter des Funktionstemplates ist, wird P zu einer Lvalue-Referenz deduziert, falls das Funktionsargument ein Lvalue war. Also:</p>
<pre><code>// Je nachdem, was T ist, kann T&amp;&amp; auch eine Lvalue-Reverenz sein
template&lt;class T&gt; void sink(T&amp;&amp;);

struct blah {};

blah         source1(); // liefert [b]R[/b]value, genauer: [b]PR[/b]value (pure rvalue)
blah      &amp;&amp; source2(); // liefert [b]R[/b]value, genauer: [b]X[/b]value (eXpiring/eXpendable)
blah      &amp;  source3(); // liefert [b]L[/b]value

void test() {
  //                  T        T &amp;&amp;
  // ---------------------------------
  sink(source1()); // blah     blah &amp;&amp;
  sink(source2()); // blah     blah &amp;&amp;
  sink(source3()); // blah &amp;   blah &amp; (reference collapsing)
}
</code></pre>
<p>Was in einer Deiner Funktionen (oder Konstruktoren) passiert, die/der eine Rvalue-Referenz entgegen nimmt, ist ganz allein Deine Sache. Du darfst das Objekt aber verändern, ohne dass es jemanden stören würde (auch den Aufrufer nicht), da es entweder ein &quot;temporäres Objekt&quot; ist oder weil der Aufrufer explizit durch ein std::move oder std::forward&lt;U&gt; (wobei U keine Lvalue-Referenz ist) gesagt hat, dass es <em>irgendwie verändert werden darf</em>. Es wird jedenfalls nichts einfach so &quot;zerstört&quot;, nur weil Du Rvalue-Referenz-Parameter benutzt.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1991654</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1991654</guid><dc:creator><![CDATA[krümelkacker]]></dc:creator><pubDate>Wed, 08 Dec 2010 20:23:24 GMT</pubDate></item><item><title><![CDATA[Reply to boost::ptr_vector mit unkopierbaren Objekten on Thu, 09 Dec 2010 00:46:02 GMT]]></title><description><![CDATA[<p>Vielen Dank, krümelkacker, für die ausführlichen Erklärungen.</p>
<p>Was mich jetzt noch zu dem &quot;reference collapsing&quot; interessiert:</p>
<pre><code class="language-cpp">template&lt;class T&gt;
void f(T&amp;&amp; t)   //&lt;-- aha, ich nehme einen RValue, also ein temporäres Objekt
{
    T t2(std::move(t));   //&lt;-- also darf es &quot;zerstört&quot; werden
}
</code></pre>
<p>Nur leider darf es ja eben nicht &quot;zerstört&quot; werden, wenn eigentlich ein LValue übergeben wurde.<br />
Ich darf also trotz RValue-Referenz nicht mehr davon ausgehen, dass das Objekt nicht mehr gebraucht wird. Wo ist also die eigentliche Idee hinter den RValue-Referenzen hin?</p>
<p>Sollte man stattdessen im Beispiel <code>std::forward</code> benutzen? (den Unterschied zwischen <code>std::forward</code> und <code>std::move</code> habe ich nie so richtig verstanden, beide machen doch aus ihrem Argument eine RValue - oder nicht?)<br />
Oder ist das <code>T&amp;&amp;</code> eher gedacht für &quot;mir ist egal, was du mir gibst, Hauptsache auf möglichst performante Weise und ich möchte nicht umständlich überladen, um R- und LValue zu unterscheiden&quot; und wenn man <code>t</code> wirklich zerstören will (es also ein &quot;echter&quot; RValue sein soll) man eine getrennte Überladung für <code>T&amp;</code> anbieten soll (oder mit <code>=delete</code> entfernen)? Dann erschliest sich mir aber gerade nicht, warum <code>T&amp;&amp;</code> besser als <code>const T&amp;</code> ist.</p>
<p>Wahrscheinlich sind die Antworten auf diese Fragen ganz einfach. Jedoch habe ich bisher im Internet nur teils wiedersprüchliche Erklärungen gefunden. Es wäre also nett, wenn du mir mal die Augen öffnen könntest. <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/1991723</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1991723</guid><dc:creator><![CDATA[ipsec]]></dc:creator><pubDate>Thu, 09 Dec 2010 00:46:02 GMT</pubDate></item><item><title><![CDATA[Reply to boost::ptr_vector mit unkopierbaren Objekten on Thu, 09 Dec 2010 07:53:22 GMT]]></title><description><![CDATA[<blockquote>
<p>Nur leider darf es ja eben nicht &quot;zerstört&quot; werden, wenn eigentlich ein LValue übergeben wurde.<br />
Ich darf also trotz RValue-Referenz nicht mehr davon ausgehen, dass das Objekt nicht mehr gebraucht wird. Wo ist also die eigentliche Idee hinter den RValue-Referenzen hin?</p>
</blockquote>
<p>Ich habe das so verstanden, dass man einen LValue übergibt, wenn er sonst nirgends mehr verwindet wird. Somit kann der LValue auch zerstört werden.</p>
<p>Wie hier beschrieben:</p>
<blockquote>
<p>Moving From Lvalues</p>
<p>All these move optimizations have one thing in common: they occur when we’re through using the source object. Sometimes, though, we need to give the compiler a hint. For example:</p>
</blockquote>
<pre><code>void g(X);

void f()
{
    X b;
    g(b);
    …
    g(b);
}
</code></pre>
<blockquote>
<p>In line 8, we call g with an lvalue, which is ineligible for resource-stealing—even though we’re never going to use b again. To tell the compiler that it can move from b, we can pass it through std::move:</p>
</blockquote>
<p>void g(X);</p>
<pre><code>void f()
{
    X b;
    g(b);              // still need the value of b
    …
    g( std::move(b) ); // all done with b now; grant permission to move
}
</code></pre>
<blockquote>
<p>Note that std::move doesn’t itself do any moving. It merely converts its argument into an rvalue reference so that move optimizations can kick in if it is used in a “move-optimized” context. When you see std::move, you should think: “grant permission to move. You can also think of std::move(a) as a descriptive way to write static_cast&lt;X&amp;&amp;&gt;(a).</p>
</blockquote>
<p>Ich hoffe ich habe das richtig verstanden.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1991747</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1991747</guid><dc:creator><![CDATA[ScyllaIllciz]]></dc:creator><pubDate>Thu, 09 Dec 2010 07:53:22 GMT</pubDate></item><item><title><![CDATA[Reply to boost::ptr_vector mit unkopierbaren Objekten on Thu, 09 Dec 2010 08:12:49 GMT]]></title><description><![CDATA[<p>ipsec schrieb:</p>
<blockquote>
<p>Was mich jetzt noch zu dem &quot;reference collapsing&quot; interessiert:</p>
<pre><code class="language-cpp">template&lt;class T&gt;
void f(T&amp;&amp; t)   //&lt;-- aha, ich nehme einen RValue, also ein temporäres Objekt
{
    T t2(std::move(t));   //&lt;-- also darf es &quot;zerstört&quot; werden
}
</code></pre>
<p>Nur leider darf es ja eben nicht &quot;zerstört&quot; werden, wenn eigentlich ein LValue übergeben wurde.</p>
</blockquote>
<p>Wegen der Template-Argument-Deduktionsregel und dem Reference-Collapsing kann aus t eben auch eine Lvalue-Referenz werden! Wenn Du T&amp;&amp; als Parameter benutzt und T wird deduziert ist das quasi ein &quot;Ich nehm alles&quot;-Parameter. Rvalue-Referenzen binden immer noch nur Rvalues, aber t muss hier keine Rvalue-Referenz sein. Die Information, ob der Aufrufer uns ein Lvalue oder Rvalue gegeben hat steckt sozusagen in dem Typ T. Und diese Wert-Kategorie kann mit std::forward wieder hergestellt werden:</p>
<pre><code class="language-cpp">template&lt;class T&gt;
void f(T&amp;&amp; t)   //&lt;-- &quot;Ich nehme alles&quot;, Lvalues und Rvalues
{
    T t2(std::forward&lt;T&gt;(t));
}
</code></pre>
<p>std::forward hat den Return-Typen T&amp;&amp;. Es liefert also entweder eine unbenannte Lvalue-Referenz (wenn T eine Lvalue-Referenz ist) oder eine Rvalue-Referenz (sonst). Dementsprechend wird möglicherweise ein Move-Konstruktor aufgerufen, falls Du f mit einem Rvalue aufrufst und mit einem Copy-Konstruktor sonst. Das ganze nennt man jetzt &quot;Perfect Forwarding&quot;. &quot;Perfekt&quot; deswegen, weil die Lvalue/Rvalue-Eigenschaft des originalen Ausdrucks wieder hergestellt werden kann und der Parameter damit so weitergeleitet werden kann, wie man ihn bekommen hat:</p>
<pre><code class="language-cpp">void foo(int&amp;);  // #1
void foo(int&amp;&amp;); // #2

template&lt;class T&gt; void bar(T&amp;&amp; x) { foo(std::forward&lt;T&gt;(x)); }

void test() {
  using std::move;
  int i = 5;
  bar(i);       // T=int&amp;, T&amp;&amp;=int&amp;  --&gt; foo #1
  bar(23);      // T=int,  T&amp;&amp;=int&amp;&amp; --&gt; foo #2
  bar(move(i)); // T=int,  T&amp;&amp;=int&amp;&amp; --&gt; foo #2
}
</code></pre>
<p>Lässt Du das forward weg, wird immer #1 aufgerufen, weil x, da eine <em>benannte</em> Referenz, immer ein Lvalue-Ausdruck ist. Ersetzt Du forward durch move, wird immer #2 aufgerufen.</p>
<p>Auf der einen Seite ist die Sonderregel der Template-Argument-Dedutkions praktisch, weil sie &quot;Perfect Forwarding&quot; erlaubt. Auf der anderen Seite kann es eine böse Überraschung geben, wenn man nicht darauf achtet:</p>
<pre><code class="language-cpp">template&lt;class T&gt; void dings(T const&amp;); // #1
template&lt;class T&gt; void dings(T&amp;&amp;);      // #2

void test2() {
  int i = 99;
  dings(i); // ruft dings #2 auf !!!
  // weil Parameter-Typ &quot;int&amp;&quot; ein besserer Match als &quot;int const&amp;&quot; ist.
}
</code></pre>
<p>ipsec schrieb:</p>
<blockquote>
<p>Sollte man stattdessen im Beispiel <code>std::forward</code> benutzen? (den Unterschied zwischen <code>std::forward</code> und <code>std::move</code> habe ich nie so richtig verstanden, beide machen doch aus ihrem Argument eine RValue - oder nicht?)</p>
</blockquote>
<p>Ob Du std::forward verwenden solltest, hängt davon ab, was Die Funktion machen soll. Der Unterschied zwischen move und forward ist folgender: move liefert immer eine Rvalue-Referenz. forward muss immer mit einem explizit angegebenen Template-Parameter aufgerufen werden. In Abhängigkeit dieses Template-Parameters liefert forward entweder eine Lvalue-Referenz oder Rvalue-Referenz und kann damit die &quot;Wertigkeit&quot; des originalen Ausdrucks wieder herstellen.</p>
<p>ipsec schrieb:</p>
<blockquote>
<p>Oder ist das <code>T&amp;&amp;</code> eher gedacht für &quot;mir ist egal, was du mir gibst,</p>
</blockquote>
<p>Wenn T ein Template-Paarameter des Funktionstemplate ist und Du T&amp;&amp; als Funktionsparametertyp verwendest ist das ein &quot;Ich fange alles und merke mir über den Typ T die originale Wertigkeit&quot;-Parameter.</p>
<p>ipsec schrieb:</p>
<blockquote>
<p>Dann erschliest sich mir aber gerade nicht, warum <code>T&amp;&amp;</code> besser als <code>const T&amp;</code> ist.</p>
</blockquote>
<p>Dich zwingt ja keiner. Es kommt darauf an, was Du machen willst.</p>
<p>kk</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1991753</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1991753</guid><dc:creator><![CDATA[krümelkacker]]></dc:creator><pubDate>Thu, 09 Dec 2010 08:12:49 GMT</pubDate></item><item><title><![CDATA[Reply to boost::ptr_vector mit unkopierbaren Objekten on Thu, 09 Dec 2010 08:17:15 GMT]]></title><description><![CDATA[<p>Vielen Dank, das war sehr erleuchtend!<br />
Kurz: <code>T&amp;&amp;</code> kann genauso wie <code>const T&amp;</code> &quot;alles&quot; nehmen, ermöglicht aber Perfect Forwarding (weil man anhand von <code>T</code> zwischen L- und RValue unterscheiden kann). Nun verstehe ich endlich auch den Sinn von <code>std::forward</code> und warum man bei diesem explizit den Typ angeben muss.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1991759</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1991759</guid><dc:creator><![CDATA[ipsec]]></dc:creator><pubDate>Thu, 09 Dec 2010 08:17:15 GMT</pubDate></item><item><title><![CDATA[Reply to boost::ptr_vector mit unkopierbaren Objekten on Thu, 09 Dec 2010 08:29:42 GMT]]></title><description><![CDATA[<p>ScyllaIllciz schrieb:</p>
<blockquote>
<blockquote>
<p>Nur leider darf es ja eben nicht &quot;zerstört&quot; werden, wenn eigentlich ein LValue übergeben wurde.<br />
Ich darf also trotz RValue-Referenz nicht mehr davon ausgehen, dass das Objekt nicht mehr gebraucht wird. Wo ist also die eigentliche Idee hinter den RValue-Referenzen hin?</p>
</blockquote>
<p>Ich habe das so verstanden, dass man einen LValue übergibt, wenn er sonst nirgends mehr verwindet wird. Somit kann der LValue auch zerstört werden.</p>
</blockquote>
<p>Andersherum. Ein Name (in einem Ausdruck), der sich auf ein Objekt bezieht -- das schließt auch benannte Referenzen ein -- ist immer ein Lvalue-Ausdruck. Temporäre Objekte haben keinen Namen. Ein Funktionsaufruf, welcher per Wert einen vector&lt;int&gt; zurück gibt ist ein Rvalue-Ausdruck. Ein Funktionsaufruf, der eine Lvalue-Referenz zurück gibt ist natürlich auch ein Lvalue-Ausdruck. Ein Lvalue-Ausdruck bezieht sich immer auf ein Objekt. Ein Rvalue-Ausdruck muss sich nicht unbedingt auf ein Objekt im Sinne von C++ beziehen. Rvalues von skalaren Typen (int,double,void*) sind keine Objekte, sondern einfach nur Werte.</p>
<p>Wenn man jetzt also schon zwischen Lvalues und Rvalues mit diesen zwei Referenztypen unterscheiden kann und durch das &quot;Klauen von Resourcen&quot; bei Rvalues unnötiges Kopieren vermeiden kann, ohne dass es jemanden stören würde, dann brauchen wir auch eine Syntax, um explizit sagen zu können, dass uns der Erhalt des Zustands eines bestimmten Objekts nicht mehr wichtig ist. Dafür ist std::move da.</p>
<p>ScyllaIllciz schrieb:</p>
<blockquote>
<p>Wie hier beschrieben:</p>
<blockquote>
<p>Moving From Lvalues</p>
</blockquote>
</blockquote>
<p>Dieser Abschnitt bezieht sich genau darauf, wie manexplizit aus Lvalues Rvalues machen kann, um zB unnötiges Kopieren zu vermeiden.</p>
<p>kk</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1991767</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1991767</guid><dc:creator><![CDATA[krümelkacker]]></dc:creator><pubDate>Thu, 09 Dec 2010 08:29:42 GMT</pubDate></item><item><title><![CDATA[Reply to boost::ptr_vector mit unkopierbaren Objekten on Thu, 09 Dec 2010 10:03:19 GMT]]></title><description><![CDATA[<p><a class="plugin-mentions-user plugin-mentions-a" href="https://www.c-plusplus.net/forum/uid/24868">@krümelkacker</a></p>
<blockquote>
<p>Andersherum. Ein Name (in einem Ausdruck), der sich auf ein Objekt bezieht -- das schließt auch benannte Referenzen ein -- ist immer ein Lvalue-Ausdruck. Temporäre Objekte haben keinen Namen. Ein Funktionsaufruf, welcher per Wert einen vector&lt;int&gt; zurück gibt ist ein Rvalue-Ausdruck. Ein Funktionsaufruf, der eine Lvalue-Referenz zurück gibt ist natürlich auch ein Lvalue-Ausdruck. Ein Lvalue-Ausdruck bezieht sich immer auf ein Objekt. Ein Rvalue-Ausdruck muss sich nicht unbedingt auf ein Objekt im Sinne von C++ beziehen. Rvalues von skalaren Typen (int,double,void*) sind keine Objekte, sondern einfach nur Werte.</p>
</blockquote>
<p>Das ist mir klar.</p>
<p>Das daraus explizit ein RValue gemacht wird ist mir auch klar.</p>
<p>Aber ich hatte das hier</p>
<blockquote>
<p>In line 8, we call g with an lvalue, which is ineligible for resource-stealing—even though we’re never going to use b again.</p>
</blockquote>
<p>so verstanden, dass &quot;b&quot; danach nicht mehr benutzt werden kann!? Was passiert bei einem erneuten Zugriff auf &quot;b&quot;? So wie ich es in dem Beitrag gelesen/verstanden habe, wird nach der Umwandlung in ein RValue, &quot;b&quot; zerstört, irre ich mich da?</p>
<p>Anyway, vielen Dank für Deine richtig guten Erklärungen!!!</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1991811</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1991811</guid><dc:creator><![CDATA[ScyllaIllciz]]></dc:creator><pubDate>Thu, 09 Dec 2010 10:03:19 GMT</pubDate></item><item><title><![CDATA[Reply to boost::ptr_vector mit unkopierbaren Objekten on Thu, 09 Dec 2010 12:02:24 GMT]]></title><description><![CDATA[<p>ScyllaIllciz schrieb:</p>
<blockquote>
<p>Aber ich hatte das hier</p>
<blockquote>
<p>In line 8, we call g with an lvalue, which is ineligible for resource-stealing—even though we’re never going to use b again.</p>
</blockquote>
<p>so verstanden, dass &quot;b&quot; danach nicht mehr benutzt werden kann!?</p>
</blockquote>
<p>Ich glaube, Du hast den Text falsch verstanden. Hier nochmal das Beispiel dazu:</p>
<pre><code>void g(X t);

void f()
{
    X b;
    g(b);
    …
    g(b);
}
</code></pre>
<p>In Zeile 6 und in Zeile 8 wird g mit b aufgerufen. Und dieses b ist immer ein Lvalue-Ausdruck. Um das Funktions-lokale Objekt t zu erzeugen, wird also in beiden Fällen ein Konstruktor benutzt, der ein Lvalue-Ausdruck vom Typ X akzeptiert. Einen solchen Konstruktor nennen wir Kopierkonstruktor und wird typischerweise mit X(X const&amp;) deklariert. Da aber b in f nach der 8. Zeile sowieso nicht mehr benötigt wird, kann es einem auch egal sein, was mit b passiert. Durch ein explizites move...</p>
<pre><code>void g(X t);

void f()
{
    X b;
    g(b);
    …
    g(std::move(b));
}
</code></pre>
<p>...kann man dafür sorgen, dass t für den letzten Funktionsaufruf von g eventuell &quot;Move-konstruiert&quot; wird. Wenn X also einen Move-Konstruktor hat -- X::X(X&amp;&amp;) -- wird hier jetzt dadurch, dass std::move(b) ein Rvalue-Ausdruck ist, der Move-Konstruktor von X für t verwendet.</p>
<p>Was in diesem Move-Konstruktor passiert ist ganz allein die Sache des Klassen-Designers. Man kann natürlich in dem Move-Konstruktor das Quellobjekt verändern, wenn das etwas bringt. Erlaubt ist es, weil eine solche Änderung entweder keiner merken kann oder weil der Nutzer dies explizit erlaubt hat (durch std::move oder std::forward). Der Compiler macht hier jedenfalls nichts besonderes. Nach dem Funktionsaufruf wird b automatisch zerstört (Destruktor aufgerufen), wie es immer schon der Fall bei automatischen Objekten war, wenn der Scope verlassen wird...</p>
<p>Ganz einfaches Beispiel:</p>
<pre><code class="language-cpp">#include &lt;algorithm&gt;

template&lt;class T&gt;
class unique_ptr
{
  T* ptr;

public:
  explicit unique_ptr(T* p=0)
  : ptr(p) {}

  unique_ptr(unique_ptr&amp;&amp; x)
  : ptr(x.ptr) {x.ptr=0;}

  friend void swap(unique_ptr&amp; a, unique_ptr&amp; b)
  { std::swap(a.ptr,b.ptr); }

  unique_ptr&amp; operator=(unique_ptr temp) &amp;
  { swap(*this,temp); return *this; }

  ~unique_ptr()
  { delete ptr; }

  T&amp; operator*() const {return *ptr;}
  T* operator-&gt;() const {return ptr;}

  explicit operator bool() const {return ptr!=0;}
  bool operator!() const         {return ptr==0;}
};

#include &lt;iostream&gt;
using namespace std;

struct big_momma {
  double foo;
  int bar[999];
};

unique_ptr&lt;big_momma&gt; source()
{
  unique_ptr&lt;big_momma&gt; up ( new big_momma() );
  up-&gt;foo = 3.14159265;
  up-&gt;bar[666] = 1729;
  return up;
}

void sink(unique_ptr&lt;big_momma&gt; up)
{
  cout &lt;&lt; up-&gt;foo &lt;&lt; &quot;, &quot; &lt;&lt; up-&gt;bar[666] &lt;&lt; '\n';
}

int main() {
  sink(source());
}
</code></pre>
<p>unique_ptr ist hier ein &quot;Move-Only&quot;-Typ. Man kann Objekte dieses Typs nicht kopieren, sondern nur &quot;umziehen lassen&quot;. Damit kann man sie an Funktionen übergeben und aus Funktionen zurückgeben. Es ist aber durch den Move-Konstruktor sichergestellt, dass nie zwei unique_ptr-Instanzen auf dasselbe Objekt zeigen -- es sei denn, man initialisiert zwei unique_ptr-Instanzen mit dem gleichen Zeigerwert selbst. Das ist dann aber ein Nutzer-Fehler und nicht im eigentlichen Sinne. Es wird dadurch sichergestellt, weil beim &quot;Umziehen&quot; der Zeiger ptr im Quellobjekt auf 0 gesetzt wird. Diese Aktion ist unbedenklich, weil es keinen stören kann. Entweder handelte es sich um ein temporäres Objekt oder der Nutzer hat es explizit erlaubt (std::move, std::forward).</p>
<p>Wie man sieht, muss ich hier auch nirgends wo ein std::move einsetzen. Das ist nur dazu da, explizit aus einem Lvalue ein Rvalue zu machen. Hier ist das nicht notwendig; denn das Objekt &quot;up&quot; in source wurde lokal erzeugt und wird zurückgegeben (und daher als Rvalue im return-Statement behandelt) und der Ausdruck &quot;source()&quot; ist ebenfalls ein Rvalue. Ein schlauer Compiler kann hier sogar die Moves wegoptimieren, so dass nur ein einziges unique_ptr-Objekt erzeugt und dann wieder zerstört wird. Im &quot;schlimmsten Fall&quot; werden drei unique_ptr-Objekte erzeugt, die sich mit der Verwaltung des erzeugten big_momma-Obejekts abwechseln.</p>
<p>kk</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1991839</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1991839</guid><dc:creator><![CDATA[krümelkacker]]></dc:creator><pubDate>Thu, 09 Dec 2010 12:02:24 GMT</pubDate></item><item><title><![CDATA[Reply to boost::ptr_vector mit unkopierbaren Objekten on Thu, 09 Dec 2010 11:16:40 GMT]]></title><description><![CDATA[<p><a class="plugin-mentions-user plugin-mentions-a" href="https://www.c-plusplus.net/forum/uid/24868">@Krümelkacker</a><br />
Danke für die Erklärung. Ich habe tatsächlich nicht daran gedacht, dass hier der Kopierkonstruktor aufgerufen wird. Dann ist der Rest auch klar.</p>
<p>Nochmal vielen Dank!!!</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1991851</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1991851</guid><dc:creator><![CDATA[ScyllaIllciz]]></dc:creator><pubDate>Thu, 09 Dec 2010 11:16:40 GMT</pubDate></item></channel></rss>