<?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[Move-Semantik]]></title><description><![CDATA[<p>Moin,</p>
<p>ich habe aktuell ein Problem bei der Umsetzung von Move-Semantiken für eine meiner Klassen:</p>
<pre><code class="language-cpp">class A{
     private:
     int *ptr;
     public:
     A(A&amp; a){
       ptr = a.ptr;
       a.ptr=NULL  
     }

     ~A(){
          if(ptr!=NULL){
               delete ptr;
          }
      }

};
</code></pre>
<p>Hauptsächlich besteht das Problem darin, dass ich obiges Konstrukt nicht als Rückgabewert von Funktionen nutzen kann, da kein Copy-Konstruktor für const-As existiert. Und bei Hinzunahme von const im Copy-Konstruktor könnte ich logischerweise den Zeiger nicht mehr modifizieren.<br />
Wie löse ich das Problem, ohne auf rvalues setzen zu müssen?</p>
]]></description><link>https://www.c-plusplus.net/forum/topic/261142/move-semantik</link><generator>RSS for Node</generator><lastBuildDate>Mon, 07 Sep 2026 13:27:37 GMT</lastBuildDate><atom:link href="https://www.c-plusplus.net/forum/topic/261142.rss" rel="self" type="application/rss+xml"/><pubDate>Sun, 14 Feb 2010 13:28:23 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to Move-Semantik on Sun, 14 Feb 2010 13:28:23 GMT]]></title><description><![CDATA[<p>Moin,</p>
<p>ich habe aktuell ein Problem bei der Umsetzung von Move-Semantiken für eine meiner Klassen:</p>
<pre><code class="language-cpp">class A{
     private:
     int *ptr;
     public:
     A(A&amp; a){
       ptr = a.ptr;
       a.ptr=NULL  
     }

     ~A(){
          if(ptr!=NULL){
               delete ptr;
          }
      }

};
</code></pre>
<p>Hauptsächlich besteht das Problem darin, dass ich obiges Konstrukt nicht als Rückgabewert von Funktionen nutzen kann, da kein Copy-Konstruktor für const-As existiert. Und bei Hinzunahme von const im Copy-Konstruktor könnte ich logischerweise den Zeiger nicht mehr modifizieren.<br />
Wie löse ich das Problem, ohne auf rvalues setzen zu müssen?</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1855404</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1855404</guid><dc:creator><![CDATA[Matzer]]></dc:creator><pubDate>Sun, 14 Feb 2010 13:28:23 GMT</pubDate></item><item><title><![CDATA[Reply to Move-Semantik on Sun, 14 Feb 2010 13:34:42 GMT]]></title><description><![CDATA[<p>Beim Smartpointers mit Ownership Transfer (wie z.B. std::auto_ptr&lt;T&gt;) ist der Copy Ctor mit einem non- const ref. Argument zwingend.</p>
<p>Warum nimmst Du nicht std::auto_ptr&lt;T&gt;?</p>
<p>Simon</p>
<p>Edit: BTW, die null Abfrage vor dem delete ist überflüssig!</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1855405</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1855405</guid><dc:creator><![CDATA[theta]]></dc:creator><pubDate>Sun, 14 Feb 2010 13:34:42 GMT</pubDate></item><item><title><![CDATA[Reply to Move-Semantik on Sun, 14 Feb 2010 13:34:36 GMT]]></title><description><![CDATA[<p>Mach den ptr mutable.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1855408</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1855408</guid><dc:creator><![CDATA[Michael E.]]></dc:creator><pubDate>Sun, 14 Feb 2010 13:34:36 GMT</pubDate></item><item><title><![CDATA[Reply to Move-Semantik on Sun, 14 Feb 2010 13:37:16 GMT]]></title><description><![CDATA[<blockquote>
<p>Hauptsächlich besteht das Problem darin, dass ich obiges Konstrukt nicht als Rückgabewert von Funktionen nutzen kann, da kein Copy-Konstruktor für const-As existiert</p>
</blockquote>
<p>Wie sollte der hier auch Sinn machen? Du möchtest das Objekt ja verändern und dann macht es keinen Sinn ein const-Objekt zurück zu liefern.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1855411</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1855411</guid><dc:creator><![CDATA[drakon]]></dc:creator><pubDate>Sun, 14 Feb 2010 13:37:16 GMT</pubDate></item><item><title><![CDATA[Reply to Move-Semantik on Sun, 14 Feb 2010 14:28:25 GMT]]></title><description><![CDATA[<blockquote>
<p>Wie sollte der hier auch Sinn machen? Du möchtest das Objekt ja verändern und dann macht es keinen Sinn ein const-Objekt zurück zu liefern.</p>
</blockquote>
<p>Der Satz hätte vielleicht eher lauten sollen: &quot;Da kein Copy-Konstruktor für A existieren <strong>kann</strong>, der const As akzeptiert...&quot;.<br />
Wie dem auch sei, ich gebe das const in diesem Fall ja nicht vor:</p>
<pre><code class="language-cpp">A getA(){
   A a;
   return a;
}
A a = getA();    // Compilerfehler, falls A keinen Copy-Ctor für const A&amp; besitzt
</code></pre>
<p>Oder wie meintest du das?</p>
<blockquote>
<p>Edit: BTW, die null Abfrage vor dem delete ist überflüssig!</p>
</blockquote>
<p>Wusste garnicht, dass einem delete die Überprüfung schon abnimmt <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f62e.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--face_with_open_mouth"
      title=":open_mouth:"
      alt="😮"
    /></p>
<blockquote>
<p>Warum nimmst Du nicht std::auto_ptr&lt;T&gt;?</p>
</blockquote>
<p>Verschiebt dies das Problem nicht nur? Wenn ich anstatt des rohen Zeigers nun den auto_ptr aus der konstanten A-Referenz ziehen möchte, müsste ich doch den gleichen Fehler bekommen?</p>
<blockquote>
<p>Mach den ptr mutable.</p>
</blockquote>
<p>Das schaue ich mir gleich mal an.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1855455</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1855455</guid><dc:creator><![CDATA[Matzer]]></dc:creator><pubDate>Sun, 14 Feb 2010 14:28:25 GMT</pubDate></item><item><title><![CDATA[Reply to Move-Semantik on Sun, 14 Feb 2010 14:33:25 GMT]]></title><description><![CDATA[<p>Meine Kenntnisse über die Move-Geschichte ist vllt. schon etwas angestaubt, aber damals sah das so aus:</p>
<pre><code class="language-cpp">struct A
{
    A(A&amp;&amp; a);
};
</code></pre>
<p>Also zwei &quot;&amp;&quot;!<br />
Dann kannst du weiterhin deinen Copy-CTor anbieten.<br />
Vllt. ist das ja der ganze Fehler.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1855459</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1855459</guid><dc:creator><![CDATA[Nöterich]]></dc:creator><pubDate>Sun, 14 Feb 2010 14:33:25 GMT</pubDate></item><item><title><![CDATA[Reply to Move-Semantik on Sun, 14 Feb 2010 17:51:34 GMT]]></title><description><![CDATA[<p>Wenn du schon rvalue-refernzen arbeiten kannst, ist das der sinnvollste Weg. Ansonsten kann ein auto_ptr-artiger Ansatz helfen:</p>
<pre><code class="language-cpp">class A
{
private:
     int* ptr;
     class Aref
     {
         A&amp; a;
     public:
         Aref(A&amp; a) : a(a) {}
         int* move() { int* p = a.ptr; a.ptr = 0; return p; }
     };
     friend class Aref;
public:
     A(A&amp; a) : ptr( Aref( a ).move() ) {}
     A(Aref ref) : ptr( ref.move() ) {}
     ~A(){
          if(ptr!=0)
               delete ptr;
     }
     A&amp; operator=(A&amp; a) { ptr = Aref( a ).move(); return *this; }
     A&amp; operator=(Aref ref) { ptr = ref.move(); return *this; }
     operator Aref() { return Aref( *this ); }
};
</code></pre>
<p>Das Ganze funktioniert allerdings nicht, falls daneben noch normale Copy-Semantik angeboten werden muss, oder zusätzliche Konvertierungen zwischen As (man denke auto_ptr mit kompatiblen Typen) benötigt werden.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1855574</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1855574</guid><dc:creator><![CDATA[camper]]></dc:creator><pubDate>Sun, 14 Feb 2010 17:51:34 GMT</pubDate></item><item><title><![CDATA[Reply to Move-Semantik on Mon, 15 Feb 2010 08:41:51 GMT]]></title><description><![CDATA[<p>Dieser Artikel aus dem Jahr 2003 (pre-Rvalue-Referenzen) ist vielleicht nicht ganz uninteressant:<br />
<a href="http://www.drdobbs.com/cpp/184403855;?_requestid=268543" rel="nofollow">&quot;Move Constructors&quot;</a>.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1855752</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1855752</guid><dc:creator><![CDATA[krümelkacker]]></dc:creator><pubDate>Mon, 15 Feb 2010 08:41:51 GMT</pubDate></item><item><title><![CDATA[Reply to Move-Semantik on Mon, 15 Feb 2010 10:12:50 GMT]]></title><description><![CDATA[<p>Beispiel eines einfachen &quot;move-only&quot;-Typs <em>ohne destruktive Kopie</em> und <em>ohne Rvalue-Referenzen</em>:</p>
<pre><code class="language-cpp">#include &lt;iostream&gt;

//-----[ simple unique_ptr emulation in C++03 ]-----

template&lt;class T&gt;
class unique_ptr
{
	T* ptr;
	struct proxy { T* ptr; };
	unique_ptr(unique_ptr&amp;);     // non-const lvalues bind here
	void operator=(unique_ptr&amp;); // non-const lvalues bind here
public:
	explicit unique_ptr(T* p=0) : ptr(p) {}

	~unique_ptr() {delete ptr;}

	unique_ptr(proxy t) : ptr(t.ptr) {}

	unique_ptr&amp; operator=(proxy t)
	{
		delete ptr;
		ptr = t.ptr;
		return *this;
	}

	T* release()
	{
		T* r = ptr;
		ptr = 0;
		return r;
	}

	operator proxy() // non-const unique_ptr --&gt; proxy
	{
		proxy r = {ptr};
		ptr = 0;
		return r;
	}

	friend unique_ptr move(unique_ptr&amp; lvalue)
	{ return unique_ptr(lvalue.release()); }

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

//-----[ example program ]-----

unique_ptr&lt;int&gt; source(int z)
{
	unique_ptr&lt;int&gt; p ( new int );
	*p = z;
	return move(p);
}

void sink(unique_ptr&lt;int&gt; p)
{
	std::cout &lt;&lt; *p &lt;&lt; '\n';
}

int main()
{
	sink(source(23));
	unique_ptr&lt;int&gt; p = source(42);
	p = source(99);
	unique_ptr&lt;int&gt; q;
	q = move(p);
	sink(move(q));
}
</code></pre>
<p>An den Stellen, an denen <code>move</code> benutzt wird, geht es nicht ohne <code>move</code> ==&gt; keine versehentlich destruktiven Kopien.</p>
<p>Zumindest funktioniert das mit dem G++ Compiler.</p>
<p>Gruß,<br />
SP</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1855801</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1855801</guid><dc:creator><![CDATA[Sebastian Pizer]]></dc:creator><pubDate>Mon, 15 Feb 2010 10:12:50 GMT</pubDate></item><item><title><![CDATA[Reply to Move-Semantik on Mon, 15 Feb 2010 11:56:20 GMT]]></title><description><![CDATA[<p>Sebastian Pizer schrieb:</p>
<blockquote>
<p>Beispiel eines einfachen &quot;move-only&quot;-Typs <em>ohne destruktive Kopie</em> und <em>ohne Rvalue-Referenzen</em>:</p>
<p>An den Stellen, an denen <code>move</code> benutzt wird, geht es nicht ohne <code>move</code> ==&gt; keine versehentlich destruktiven Kopien.</p>
</blockquote>
<p>Das ist die gleiche Idee. Und so wie g++s auto_ptr ist es nicht exceptionsicher.</p>
<p>Alexandreis Mojo-System ist interessant aber imo zu komplex und aufdringlich.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1855863</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1855863</guid><dc:creator><![CDATA[camper]]></dc:creator><pubDate>Mon, 15 Feb 2010 11:56:20 GMT</pubDate></item><item><title><![CDATA[Reply to Move-Semantik on Mon, 15 Feb 2010 13:36:01 GMT]]></title><description><![CDATA[<p>camper schrieb:</p>
<blockquote>
<p>Das ist die gleiche Idee.</p>
</blockquote>
<p>Je nachdem, was Du mit &quot;Idee&quot; meinst. <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f609.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--winking_face"
      title=";-)"
      alt="😉"
    /></p>
<p>camper schrieb:</p>
<blockquote>
<p>Und so wie g++s auto_ptr ist es nicht exceptionsicher.</p>
</blockquote>
<p>Du hast Recht. Es ist nicht schön, den Zeiger im <code>struct</code> &quot;ungeschützt&quot; zwischen zu speichern. Das kann auch schon mal bei der Parameterübergabe an eine Funktion nach hinten losgehen -- denke ich.</p>
<p>Ich war vorhin noch im Glauben, dass, wenn ich im struct einen Zeiger auf unique_ptr&lt;T&gt; statt T speichere, dass es zu &quot;baumelnden Zeigern&quot; kommen kann (dass *proxy.ptr eventuell ungültig wird). Ich weiß aber nicht mehr, wie ich zu dem Schluss gekommen bin. Es müsste auch so funktionieren:</p>
<pre><code class="language-cpp">template&lt;class T&gt;
class unique_ptr
{
	T* ptr;
	struct proxy { unique_ptr&lt;T&gt;* pup; };
	unique_ptr(unique_ptr&amp;);     // non-const lvalues bind here
	void operator=(unique_ptr&amp;); // non-const lvalues bind here
public:
	explicit unique_ptr(T* p=0) : ptr(p) {}

	~unique_ptr() {delete ptr;}

	unique_ptr(proxy t) : ptr(t.pup-&gt;release()) {}

	unique_ptr&amp; operator=(proxy t)
	{
		delete ptr;
		ptr = t.pup-&gt;release();
		return *this;
	}

	T* release()
	{
		T* r = ptr;
		ptr = 0;
		return r;
	}

	operator proxy() // non-const unique_ptr --&gt; proxy
	{
		proxy r = {this};
		return r;
	}

	friend unique_ptr move(unique_ptr&amp; lvalue)
	{ return unique_ptr(lvalue.release()); }

	friend void swap(unique_ptr &amp; p1, unique_ptr &amp; p2)
	{
		T* tmp = p1.ptr;
		p1.ptr = p2.ptr;
		p2.ptr = tmp;
	}

	T&amp; operator*() const {return *ptr;}
	T* operator-&gt;() const {return ptr;}
};
</code></pre>
<p>(wobei &quot;proxy&quot; jetzt eher die Funktion einer RValue-Referenz übernimmt)</p>
<p>Sieht jemand ein mögliches Problem (mal davon abgesehen, dass ich auf benutzerdefinierte &quot;Deleter&quot; und Konvertierungen verzichtet habe)? Ich sehe im Moment keins.</p>
<p>Gruß,<br />
SP</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1855922</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1855922</guid><dc:creator><![CDATA[Sebastian Pizer]]></dc:creator><pubDate>Mon, 15 Feb 2010 13:36:01 GMT</pubDate></item><item><title><![CDATA[Reply to Move-Semantik on Mon, 15 Feb 2010 13:26:16 GMT]]></title><link>https://www.c-plusplus.net/forum/post/1855944</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1855944</guid><dc:creator><![CDATA[camper]]></dc:creator><pubDate>Mon, 15 Feb 2010 13:26:16 GMT</pubDate></item><item><title><![CDATA[Reply to Move-Semantik on Mon, 15 Feb 2010 13:43:21 GMT]]></title><description><![CDATA[<p>Ich bin nicht sicher ob ich move in dieser Form mag, dem Zweck der Funktion nach, wird sie häufig eingesetzt werden, zum Beispiel Funktionsparameter zu initialisieren. Tritt nun nach Ausführen des move und vor Aufruf der anderen Funktion eine Exception auf, besteht zwar kein Leck mehr, aber das Objekt, auf das gezeigt wurde ist weg, das eigentliche Ziel wurde nie initialisert und der ursprüngliche Zeiger ist leer. Imo ist es zweckmäßiger, move ebenfalls einen proxy zurückgeben zu lassen. Dann muss man nur entsprechend bzgl. Selbstmove aufpassen:</p>
<pre><code class="language-cpp">template&lt;class T&gt;
class unique_ptr
{
    T* ptr;
    struct proxy { unique_ptr&lt;T&gt;* ptr; };
    unique_ptr(unique_ptr&amp;);     // non-const lvalues bind here
    void operator=(unique_ptr&amp;); // non-const lvalues bind here
public:
    explicit unique_ptr(T* p=0) : ptr(p) {}

    ~unique_ptr() {delete ptr;}

    unique_ptr(proxy t) : ptr(t.ptr-&gt;release()) {}

    unique_ptr&amp; operator=(proxy t)
    {
        T* p = t.ptr-&gt;release();
        delete ptr;
        ptr = p;
        return *this;
    }

    T* release()
    {
        T* r = ptr;
        ptr = 0;
        return r;
    }

    operator proxy() // non-const unique_ptr --&gt; proxy
    {
        proxy r = {this};
        return r;
    }

    friend proxy move(unique_ptr&amp; lvalue)
    { return lvalue; }

    friend void swap(unique_ptr &amp; p1, unique_ptr &amp; p2)
    {
        T* tmp = p1.ptr;
        p1.ptr = p2.ptr;
        p2.ptr = tmp;
    }

    T&amp; operator*() const {return *ptr;}
    T* operator-&gt;() const {return ptr;}
};
</code></pre>
]]></description><link>https://www.c-plusplus.net/forum/post/1855957</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1855957</guid><dc:creator><![CDATA[camper]]></dc:creator><pubDate>Mon, 15 Feb 2010 13:43:21 GMT</pubDate></item><item><title><![CDATA[Reply to Move-Semantik on Mon, 15 Feb 2010 13:48:03 GMT]]></title><description><![CDATA[<p>Ok, das hilft auch nicht. Die Exception könnte ja auch nach Initialisierung des Funktionsparameters auftreten, dann wäre der Objekt trotzdem weg.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1855959</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1855959</guid><dc:creator><![CDATA[camper]]></dc:creator><pubDate>Mon, 15 Feb 2010 13:48:03 GMT</pubDate></item><item><title><![CDATA[Reply to Move-Semantik on Mon, 15 Feb 2010 14:00:47 GMT]]></title><description><![CDATA[<p>camper schrieb:</p>
<blockquote>
<p>Ich bin nicht sicher ob ich move in dieser Form mag, dem Zweck der Funktion nach, wird sie häufig eingesetzt werden, zum Beispiel Funktionsparameter zu initialisieren. Tritt nun nach Ausführen des move und vor Aufruf der anderen Funktion eine Exception auf, besteht zwar kein Leck mehr, aber das Objekt, auf das gezeigt wurde ist weg, das eigentliche Ziel wurde nie initialisert und der ursprüngliche Zeiger ist leer.</p>
</blockquote>
<p>Das passiert genauso auch bei dem &quot;echten unique_ptr&quot;, oder nicht?</p>
<p>camper schrieb:</p>
<blockquote>
<p>Imo ist es zweckmäßiger, move ebenfalls einen proxy zurückgeben zu lassen.</p>
</blockquote>
<p>Das war sogar ursprünglich mein Plan -- wird aber vom G++ nicht mehr akzeptiert in einer Situation wie dieser:</p>
<pre><code class="language-cpp">unique_ptr&lt;int&gt; q = move(p);
</code></pre>
<p>oder dieser</p>
<pre><code class="language-cpp">return move(p);
</code></pre>
<p>wahrscheinlich, weil es zu viele Konvertierungen wären (proxy -&gt; unique_ptr -&gt; proxy -&gt; unique_ptr) oder so ähnlich. Bind mir auch gar nicht sicher, ob ich mit meiner letzten Version einfach &quot;Glück&quot; hatte (gnädiger G++), oder ob's vom Standard her auch wirklich so funktionieren muss.</p>
<p>Gruß,<br />
SP</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1855961</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1855961</guid><dc:creator><![CDATA[Sebastian Pizer]]></dc:creator><pubDate>Mon, 15 Feb 2010 14:00:47 GMT</pubDate></item><item><title><![CDATA[Reply to Move-Semantik on Mon, 15 Feb 2010 14:06:56 GMT]]></title><description><![CDATA[<p>Sebastian Pizer schrieb:</p>
<blockquote>
<p>camper schrieb:</p>
<blockquote>
<p>Imo ist es zweckmäßiger, move ebenfalls einen proxy zurückgeben zu lassen.</p>
</blockquote>
<p>Das war sogar ursprünglich mein Plan -- wird aber vom G++ nicht mehr akzeptiert in einer Situation wie dieser:</p>
<pre><code class="language-cpp">unique_ptr&lt;int&gt; q = move(p);
</code></pre>
<p>oder dieser</p>
<pre><code class="language-cpp">return move(p);
</code></pre>
<p>wahrscheinlich, weil es zu viele Konvertierungen wären (proxy -&gt; unique_ptr -&gt; proxy -&gt; unique_ptr) oder so ähnlich. Bind mir auch gar nicht sicher, ob ich mit meiner letzten Version einfach &quot;Glück&quot; hatte (gnädiger G++), oder ob's vom Standard her auch wirklich so funktionieren muss.</p>
<p>Gruß,<br />
SP</p>
</blockquote>
<p>Weil der Zugriff auf den Copyctor von unique_ptrn icht möglich ist. Stimmt, hatte ich nicht bedacht - bisher habe ich nur mit auto_ptr-Implementationen gespielt, dort besteht das Problem nicht.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1855969</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1855969</guid><dc:creator><![CDATA[camper]]></dc:creator><pubDate>Mon, 15 Feb 2010 14:06:56 GMT</pubDate></item><item><title><![CDATA[Reply to Move-Semantik on Tue, 16 Feb 2010 13:04:07 GMT]]></title><description><![CDATA[<p>Moin,<br />
vielen Dank für die ganzen Antworten. Allerdings muss ich das Ganze erst einmal verdauen <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f609.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--winking_face"
      title=";)"
      alt="😉"
    /></p>
<p>camper schrieb:</p>
<blockquote>
<pre><code class="language-cpp">template&lt;class T&gt;
class unique_ptr
{
    T* ptr;
    struct proxy { unique_ptr&lt;T&gt;* ptr; };
    unique_ptr(unique_ptr&amp;);     // non-const lvalues bind here
    void operator=(unique_ptr&amp;); // non-const lvalues bind here
public:
    explicit unique_ptr(T* p=0) : ptr(p) {}

    ~unique_ptr() {delete ptr;}

    unique_ptr(proxy t) : ptr(t.ptr-&gt;release()) {}

    unique_ptr&amp; operator=(proxy t)
    {
        T* p = t.ptr-&gt;release();
        delete ptr;
        ptr = p;
        return *this;
    }

    T* release()
    {
        T* r = ptr;
        ptr = 0;
        return r;
    }

    operator proxy() // non-const unique_ptr --&gt; proxy
    {
        proxy r = {this};
        return r;
    }

    friend proxy move(unique_ptr&amp; lvalue)
    { return lvalue; }

    friend void swap(unique_ptr &amp; p1, unique_ptr &amp; p2)
    {
        T* tmp = p1.ptr;
        p1.ptr = p2.ptr;
        p2.ptr = tmp;
    }

    T&amp; operator*() const {return *ptr;}
    T* operator-&gt;() const {return ptr;}
};
</code></pre>
</blockquote>
<p>Der &quot;Trick&quot; mit dem Proxy ist mir neu, deswegen an dieser Stelle eine Frage dazu:<br />
Soweit ich das richtig sehe, erwartet die Klasse für den Copy-Ctor und operator= standardmäßig eine non-const Referenz auf einen anderen unique-Pointer. Für den Fall, dass dennoch eine const-Referenz von unique_ptr übergeben wird, findet zuerst eine Konvertierung von const unique_ptr-&gt;proxy statt und diesen Proxy kann ich anschließend problemlos modifizieren. Wieso funktioniert diese Konvertierung?</p>
<p>Und was bedeuten die Klammern um this in</p>
<pre><code class="language-cpp">operator proxy() // non-const unique_ptr --&gt; proxy
    {
        proxy r = {this};
        return r;
    }
</code></pre>
<p>krümelkacker schrieb:</p>
<blockquote>
<p>Dieser Artikel aus dem Jahr 2003 (pre-Rvalue-Referenzen) ist vielleicht nicht ganz uninteressant:<br />
&quot;Move Constructors&quot;.</p>
</blockquote>
<p>Vielen Dank dafür. Werde ich mir mal in Ruhe zu Gemüte führen.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1856536</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1856536</guid><dc:creator><![CDATA[Matzer]]></dc:creator><pubDate>Tue, 16 Feb 2010 13:04:07 GMT</pubDate></item><item><title><![CDATA[Reply to Move-Semantik on Tue, 16 Feb 2010 13:15:46 GMT]]></title><description><![CDATA[<p>Matzer schrieb:</p>
<blockquote>
<p>Soweit ich das richtig sehe, erwartet die Klasse für den Copy-Ctor und operator= standardmäßig eine non-const Referenz auf einen anderen unique-Pointer.</p>
</blockquote>
<p>Richtig. Und weil diese Member private und sowieso ohne Implementation sind, wird jeder Versuch, einen normalen non-const unique_ptr zu kopieren mit einem Fehler bestraft.</p>
<p>Matzer schrieb:</p>
<blockquote>
<p>Für den Fall, dass dennoch eine const-Referenz von unique_ptr übergeben wird, findet zuerst eine Konvertierung von const unique_ptr-&gt;proxy statt und diesen Proxy kann ich anschließend problemlos modifizieren. Wieso funktioniert diese Konvertierung?</p>
</blockquote>
<p>Keineswegs. Da die für die Konvertierung zuständige Operationfunktion keine const-Memberfunktion ist, kann für const-unique_ptr kein Proxy erstellt werden. Hier erfolgt also auch eine Fehlermeldung durch den Compiler.<br />
Die einzige Art unique_ptr, die kopiert wreden kann, sind non-const rvalues - also im Regelfall Rückgabewerte von Funktionen. Rvalues (temporäre Objekte) binden nicht an non-const Referenzen, weshalb copy-ctor und copy-Zuweisung keine Kandidaten sind.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1856544</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1856544</guid><dc:creator><![CDATA[camper]]></dc:creator><pubDate>Tue, 16 Feb 2010 13:15:46 GMT</pubDate></item><item><title><![CDATA[Reply to Move-Semantik on Tue, 16 Feb 2010 13:48:33 GMT]]></title><description><![CDATA[<blockquote>
<p>Die einzige Art unique_ptr, die kopiert wreden kann, sind non-const rvalues - also im Regelfall Rückgabewerte von Funktionen. Rvalues (temporäre Objekte) binden nicht an non-const Referenzen, weshalb copy-ctor und copy-Zuweisung keine Kandidaten sind.</p>
</blockquote>
<p>Ich bezog mich auch auf die Rückgabewerte von Funktionen. Nur verstehe ich gerade nicht, worin der Unterschied zwischen dem Binden des Rückgabewertes einer Funktion und einer Temporary besteht. Ich dachte folgendes wäre äquivalent:</p>
<pre><code class="language-cpp">// Sei A irgendeine Klasse
A getA(){
  A a;
  return a;
}

A oneA     = getA();  
A anotherA = A();
</code></pre>
<p>da nach der Auswertung von getA() auf der rechten Seite im Grunde auch nur eine Temporary stehen würde?</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1856588</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1856588</guid><dc:creator><![CDATA[Matzer]]></dc:creator><pubDate>Tue, 16 Feb 2010 13:48:33 GMT</pubDate></item><item><title><![CDATA[Reply to Move-Semantik on Tue, 16 Feb 2010 17:47:11 GMT]]></title><description><![CDATA[<p>Matzer schrieb:</p>
<blockquote>
<p>camper schrieb:</p>
<blockquote>
<pre><code class="language-cpp">template&lt;class T&gt;
class unique_ptr
{
    T* ptr;
    struct proxy { unique_ptr&lt;T&gt;* ptr; };
    unique_ptr(unique_ptr&amp;);     // non-const lvalues bind here
    void operator=(unique_ptr&amp;); // non-const lvalues bind here
public:

    [...]

    friend proxy move(unique_ptr&amp; lvalue)
    { return lvalue; }
</code></pre>
</blockquote>
</blockquote>
<p>Ich wollte nur nochmal darauf hinweisen, dass diese Abänderung von <code>move</code> dazu führt, dass keine Kopierinitialisierungen mehr möglich sind und damit auch <code>return move(...);</code> oder die Übergabe von <code>move(...)</code> an eine Funktion nicht mehr klappt.</p>
<p>Matzer schrieb:</p>
<blockquote>
<p>Wieso funktioniert diese Konvertierung?</p>
<p>Und was bedeuten die Klammern um this in</p>
<pre><code class="language-cpp">operator proxy() // non-const unique_ptr --&gt; proxy
    {
        proxy r = {this};
        return r;
    }
</code></pre>
</blockquote>
<p>Das ist ein Konvertierungsoperator, mit dem <em>implizit</em> unique_ptr-Objekte zu proxy-Objekten konvertiert können. Die geschweiften Klammern um <code>this</code> sind einfach Teil der Aggregats-Initialisierungs-Syntax. Der Typ proxy ist ein Aggreratstyp und der Zeiger <code>r.pup</code> wird hier durch <code>this</code> initialisiert.</p>
<p>Mal ein paar Beispiele, wie das alles funktioniert:</p>
<pre><code>unique_ptr&lt;int&gt; foo = (initialisierer);

Sei der Initialisierer ein cv-qualifizierter Ausdruck vom Typ
unique_ptr&lt;int&gt;. Dann gibt es noch 4 Möglichkeiten: Alle
Kombinationen aus const/non-const und LValue/RValue-Ausdruck.

Initialisierer: | Kopierkonstruktor | Konvertierungskonstruktor
                | kommt in Frage    | (proxy-&gt;unique_ptr)
----------------+-------------------+--------------
  const lvalue  |     nein (1)      |    nein (4)
  const rvalue  |     nein (1)      |    nein (4)
        lvalue  |       JA (2)      |      ja (5)
        rvalue  |     nein (3)      |      JA (6)

1: non-const Referenz nicht mit const Ausdruck initialisierbar
2: kommt in Frage und ist auch ein besserer Match als 5, führt
   aber zu einem Compilier-Fehler, da privat
3: non-const Referenz nicht mit RValue Ausdruck (&quot;temporäres
   Objekt&quot;) initialisierbar.
4: const unique_ptr lässt sich nicht in proxy konvertieren, da
   der Konvertierungsoperator nicht const ist.
5: kommt in Frage, ist aber ein schlechterer Match als 2
6: temporärer non-const unique_ptr kann zu proxy hin- und wieder
   zurück konvertiert werden.
</code></pre>
<p>unique_ptr ist ein &quot;move only&quot;-Typ. Richtig kopierbare Typen mit move-Konstruktor-Optimierung könnte man jetzt noch bekommen, in dem man folgende Konstruktoren und Zuweisungsoperatoren definiert:</p>
<pre><code class="language-cpp">using boost::enable_if;
using boost::is_same;

class myclass
{
  private:
    struct rval_ref { myclass&amp; ref; rval_ref(myclass*p):ref(*p){} };
  public:
    // copy from const lvalues
    template&lt;typename U&gt;
    myclass(U &amp;,
       typename enable_if&lt;
          is_same&lt;U,const myclass&gt;
       &gt;::type* =0);

    // copy from non-const lvalues
    myclass(myclass&amp;);

    // move from non-const rvalue
    myclass(rval_ref);

    // copy assign from const lvalues
    template&lt;typename U&gt;
    myclass&amp; operator=(U &amp;,
       typename enable_if&lt;
          is_same&lt;U,const myclass&gt;
       &gt;::type* =0);

    // copy assign from non-const lvalue
    myclass&amp; operator=(myclass&amp;);

    // move assign from non-const rvalue
    myclass&amp; operator=(rval_ref);

    operator rval_ref()
    { return rval_ref(this); }

    friend myclass move(myclass&amp; lvalue)
    { return myclass(rval_ref(&amp;lvalue)); }

    ...
};
</code></pre>
<p>(ungetestet), wobei der Trick mit den Templates dazu führt, dass konstante Objekte kopiert werden können, aber non-const temporäre Objekte immer noch über den rval_ref-Umweg &quot;kopiert&quot; werden.</p>
<p>Nachteil dieser Emulationen gegenüber dem, was C++0x bieten wird:</p>
<ul>
<li>Keine implizit konvertierenden Move-Operationen möglich (zB unique_ptr&lt;Derived&gt; --&gt; unique_ptr&lt;Base&gt;. Das muss stattdessen über Hilfsfunktionen erledigt werden.</li>
<li>Objekte ziehen immer mehrfach um, keine move/copy elision. Bei <code>unique_ptr&lt;int&gt; q = move(p);</code> werden zwei temporäre Objekte und 3mal der &quot;move ctor&quot; aufgerufen (zumindest unter G++).</li>
</ul>
<p>Gruß,<br />
SP</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1856610</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1856610</guid><dc:creator><![CDATA[Sebastian Pizer]]></dc:creator><pubDate>Tue, 16 Feb 2010 17:47:11 GMT</pubDate></item><item><title><![CDATA[Reply to Move-Semantik on Tue, 16 Feb 2010 14:38:16 GMT]]></title><description><![CDATA[<p>Matzer schrieb:</p>
<blockquote>
<p>Ich dachte folgendes wäre äquivalent:</p>
<pre><code class="language-cpp">// Sei A irgendeine Klasse
A getA(){
  A a;
  return a;
}

A oneA     = getA();  
A anotherA = A();
</code></pre>
<p>da nach der Auswertung von getA() auf der rechten Seite im Grunde auch nur eine Temporary stehen würde?</p>
</blockquote>
<p>Richtig. In beiden Fällen handelt es sich auf der rechten Seite um einen &quot;RValue-Ausdruck&quot;. Wenn Du &quot;A()&quot; in der zweiten Zeile durch &quot;oneA&quot; ersetzt, steht auf der rechten Seite ein &quot;LValue-Ausdruck&quot;. Das ist ein Unterschied bzgl Optimierungen oder &quot;move-only&quot;-Typen wie unique_ptr. Ein unique_ptr-Objekt soll ja nicht kopiert werden können. Man will keine destruktive Kopie (Kopie, die das Quellobjekt verändert). Und man will auch keine Doppellöschungen. Die Idee ist eben die, unique_ptr-Objekte &quot;umziehen&quot; zu lassen und das Quellobjekt nur dann zu &quot;zerstören&quot; (den Zeiger darin auf 0 zu setzen), falls es keiner merkt (temporäres Objekt) oder falls es explizit erwünscht wurde (move(...)-Syntax).</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1856623</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1856623</guid><dc:creator><![CDATA[Sebastian Pizer]]></dc:creator><pubDate>Tue, 16 Feb 2010 14:38:16 GMT</pubDate></item></channel></rss>