<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[std::mem_movable]]></title><description><![CDATA[<p>Hallo,</p>
<p>wäre es nicht sinnvoll, einen einen type trait <code>mem_movable&lt;T&gt;</code> einzuführen? Er wäre dann erfüllt, wenn eine Instanz eine Klasse per mem_cpy gemoved werden kann, wenn danach kein Destruktor auf den alten Speicher aufgerufen wird. Er müsste vermutlich für nicht-pods explizit spezialisiert werden.<br />
Vorteil wäre der, dass nicht unnötig Destruktoren aufgerufen werden, wenn sie nicht nötig sind. So könnte beispielsweise ein std::vector viel performanter wachsen, als das bisher der Fall ist.<br />
Im Grunde sind wohl fast alle Klassen mem_movable, es sei denn sie besitzen intern pointer auf eigene member bzw. move/copy Konstruktoren sind explizit deleted.<br />
Ein shared_ptr muss beispielsweise im Destruktor auf jeden fall irgendein <code>if(...)</code> ausführen, was man sich damit sparen könnte.<br />
Was haltet ihr davon?</p>
]]></description><link>https://www.c-plusplus.net/forum/topic/295306/std-mem_movable</link><generator>RSS for Node</generator><lastBuildDate>Sat, 15 Aug 2026 04:20:52 GMT</lastBuildDate><atom:link href="https://www.c-plusplus.net/forum/topic/295306.rss" rel="self" type="application/rss+xml"/><pubDate>Thu, 10 Nov 2011 22:09:43 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to std::mem_movable on Thu, 10 Nov 2011 22:09:43 GMT]]></title><description><![CDATA[<p>Hallo,</p>
<p>wäre es nicht sinnvoll, einen einen type trait <code>mem_movable&lt;T&gt;</code> einzuführen? Er wäre dann erfüllt, wenn eine Instanz eine Klasse per mem_cpy gemoved werden kann, wenn danach kein Destruktor auf den alten Speicher aufgerufen wird. Er müsste vermutlich für nicht-pods explizit spezialisiert werden.<br />
Vorteil wäre der, dass nicht unnötig Destruktoren aufgerufen werden, wenn sie nicht nötig sind. So könnte beispielsweise ein std::vector viel performanter wachsen, als das bisher der Fall ist.<br />
Im Grunde sind wohl fast alle Klassen mem_movable, es sei denn sie besitzen intern pointer auf eigene member bzw. move/copy Konstruktoren sind explizit deleted.<br />
Ein shared_ptr muss beispielsweise im Destruktor auf jeden fall irgendein <code>if(...)</code> ausführen, was man sich damit sparen könnte.<br />
Was haltet ihr davon?</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2143095</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2143095</guid><dc:creator><![CDATA[GorbGorb]]></dc:creator><pubDate>Thu, 10 Nov 2011 22:09:43 GMT</pubDate></item><item><title><![CDATA[Reply to std::mem_movable on Thu, 10 Nov 2011 22:39:23 GMT]]></title><description><![CDATA[<p>Seit C++11 ist das überflüssig. Move-Semantik kann im Prinzip ebenso performant wie memmove/memcpy implementiert werden und ist sicherer, hat mehr Anwendungsfälle und funktioniert vollautomatisch ohne zusätzlichen Trait.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2143108</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2143108</guid><dc:creator><![CDATA[ipsec]]></dc:creator><pubDate>Thu, 10 Nov 2011 22:39:23 GMT</pubDate></item><item><title><![CDATA[Reply to std::mem_movable on Fri, 11 Nov 2011 05:35:45 GMT]]></title><description><![CDATA[<p>ipsec schrieb:</p>
<blockquote>
<p>Seit C++11 ist das überflüssig. Move-Semantik kann im Prinzip ebenso performant wie memmove/memcpy implementiert werden und ist sicherer, hat mehr Anwendungsfälle und funktioniert vollautomatisch ohne zusätzlichen Trait.</p>
</blockquote>
<p>Zum einen ist mem_cpy meistens performanter, als einzeln Variablen zu verschieben, und zum andern hab ich doch beschrieben, dass man manchmal unnötigen code im Destruktor ausführt. Ein einfacher std::string könnte z.B. so aussehen:</p>
<pre><code class="language-cpp">class string
{
public:
    string( string &amp;&amp;s )
    {
        mem_begin = s.mem_begin;
        mem_end = s.mem_end;
        data_end = s.data_end;
        s.mem_begin = 0; //schon mal eine Zuweisung mehr als nötig
    }
    ~string()
    {
        delete[] mem_begin; //das ist eigentlich unnötig, wenn nur gemoved werden soll
    }
private:
    char *mem_begin;
    char *mem_end;
    char *data_end; //von mem_begin bis data_end reicht der eigentlich gespeicherte String
};
</code></pre>
<p>Pro move ist das eine Zuweisung und eine delete[] (auf 0, aber kostenlos ist das trotzdem nicht), das ohne Not aufgerufen werden muss. Außerdem wird ein großes Stück Speicher mit mem_cpy schneller kopiert werden als mit Zuweisungen à 4 Byte.</p>
<p>Im Grunde hindert einen ja nichts daran, sowas einfach selbst zu definieren. Aber ohne dass die std container das auch nutzen, bringt es leider eher wenig.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2143132</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2143132</guid><dc:creator><![CDATA[GorbGorb]]></dc:creator><pubDate>Fri, 11 Nov 2011 05:35:45 GMT</pubDate></item><item><title><![CDATA[Reply to std::mem_movable on Fri, 11 Nov 2011 09:48:40 GMT]]></title><description><![CDATA[<p>GorbGorb schrieb:</p>
<blockquote>
<p>Außerdem wird ein großes Stück Speicher mit mem_cpy schneller kopiert werden als mit Zuweisungen à 4 Byte.</p>
</blockquote>
<p>Wo steht das? Hast du Benchmarks? Der Compiler kann durchgängige 1:1 Zuweisungen nach Belieben zu einem memcpy optimieren und tut das auch.</p>
<p>GorbGorb schrieb:</p>
<blockquote>
<p>Pro move ist das eine Zuweisung und eine delete[] (auf 0, aber kostenlos ist das trotzdem nicht), das ohne Not aufgerufen werden muss.</p>
</blockquote>
<p>Ich bin mir relativ sicher, dass der Compiler die Folge <code>x = 0; delete x; &lt;end scope of x&gt;</code> problemlos erkennen und wegoptimieren kann. Jag doch mal ein simples Programm mit deiner String-Klasse durch den Compiler und schau, wie der Assembler dafür aussieht.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2143168</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2143168</guid><dc:creator><![CDATA[pumuckl]]></dc:creator><pubDate>Fri, 11 Nov 2011 09:48:40 GMT</pubDate></item><item><title><![CDATA[Reply to std::mem_movable on Fri, 11 Nov 2011 12:46:58 GMT]]></title><description><![CDATA[<p>pumuckl schrieb:</p>
<blockquote>
<p>Ich bin mir relativ sicher, dass der Compiler die Folge <code>x = 0; delete x; &lt;end scope of x&gt;</code> problemlos erkennen und wegoptimieren kann. Jag doch mal ein simples Programm mit deiner String-Klasse durch den Compiler und schau, wie der Assembler dafür aussieht.</p>
</blockquote>
<p>Das würde nur bei link-time-Optimierung funktionieren, denn ohne Kenntnis der verwendeten Deallokationsfunktion, kann der Compiler nicht wissen, ob delete[] 0 keine beobachtbaren Nebeneffekte hat. Und das ist auch der Grund weshalb</p>
<pre><code class="language-cpp">if(p!=nullptr)delete[]0;
</code></pre>
<p>eben keineswegs sinnlos ist.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2143248</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2143248</guid><dc:creator><![CDATA[camper]]></dc:creator><pubDate>Fri, 11 Nov 2011 12:46:58 GMT</pubDate></item><item><title><![CDATA[Reply to std::mem_movable on Fri, 11 Nov 2011 19:19:18 GMT]]></title><description><![CDATA[<p>pumuckl schrieb:</p>
<blockquote>
<p>GorbGorb schrieb:</p>
<blockquote>
<p>Außerdem wird ein großes Stück Speicher mit mem_cpy schneller kopiert werden als mit Zuweisungen à 4 Byte.</p>
</blockquote>
<p>Wo steht das? Hast du Benchmarks? Der Compiler kann durchgängige 1:1 Zuweisungen nach Belieben zu einem memcpy optimieren und tut das auch.</p>
<p>GorbGorb schrieb:</p>
<blockquote>
<p>Pro move ist das eine Zuweisung und eine delete[] (auf 0, aber kostenlos ist das trotzdem nicht), das ohne Not aufgerufen werden muss.</p>
</blockquote>
<p>Ich bin mir relativ sicher, dass der Compiler die Folge <code>x = 0; delete x; &lt;end scope of x&gt;</code> problemlos erkennen und wegoptimieren kann. Jag doch mal ein simples Programm mit deiner String-Klasse durch den Compiler und schau, wie der Assembler dafür aussieht.</p>
</blockquote>
<p>Ich hab mal ein benchmark gemacht:</p>
<pre><code class="language-cpp">#include &lt;iostream&gt;
#include &lt;cstring&gt;
#include &lt;ctime&gt;
#include &lt;cstring&gt;
#include &lt;vector&gt;

class my_string
{
public:
	my_string()
	{
		mem_begin = 0;
		mem_end = 0;
		data_end = 0;
	}
	my_string( my_string &amp;&amp;str )
	{
		mem_begin = str.mem_begin;
		mem_end = str.mem_end;
		data_end = str.data_end;

		str.mem_begin = 0;
	}
	~my_string()
	{
		delete[] mem_begin;
	}
private:
	char *mem_begin;
	char *mem_end;
	char *data_end;
};

const unsigned int array_size = 10000;
const unsigned int iterations = 100000;

int main()
{
	my_string *a = new my_string[ array_size ];
	my_string *b = static_cast&lt; my_string* &gt;( operator new( sizeof( my_string ) * array_size ) );

	unsigned int t;

	t = std::clock();
	for( unsigned int i = 0 ; i &lt; iterations ; ++i )
	{
		my_string *it_a = a;
		my_string *end_a = a + array_size;
		my_string *it_b = b;
		while( it_a != end_a )
		{
			new ( it_b ) my_string( std::move( *it_a ) );

			++it_a;
			++it_b;
		}
	}
	std::cout &lt;&lt; &quot;Move Constructor: &quot; &lt;&lt; std::clock() - t &lt;&lt; std::endl;

	//und zurück mit memcpy

	t = std::clock();
	for( unsigned int i = 0 ; i &lt; iterations ; ++i )
	{
		std::memcpy( a , b , array_size * sizeof( my_string ) );
	}
	std::cout &lt;&lt; &quot;memcpy: &quot; &lt;&lt; std::clock() - t &lt;&lt; std::endl;

	std::cin.get();
}
</code></pre>
<p>Ausgabe bei mir (gcc 4.5):<br />
`</p>
<p>Move Constructor: 6235</p>
<p>memcpy: 1793</p>
<p>`</p>
<p>Es wurde also offensichtlich nichts optimiert. Interessant ist noch, dass sich memcpy und move constructor bei sehr großen Arraygrößen nicht mehr so viel nehmen, dann habe ich z.B. 850 und 632.<br />
Ein std::mem_movable brächte also offensichtlich bei den heutigen compilern (oder mindestens dem gcc) Vorteile.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2143401</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2143401</guid><dc:creator><![CDATA[GorbGorb]]></dc:creator><pubDate>Fri, 11 Nov 2011 19:19:18 GMT</pubDate></item><item><title><![CDATA[Reply to std::mem_movable on Sat, 12 Nov 2011 11:19:29 GMT]]></title><description><![CDATA[<p>Können <code>std::memmove()</code> und <code>std::memcpy()</code> (übrigens ohne Underscore) nicht genau dann sinvoll angewandt werden, wenn es sich um PODs handelt?</p>
<p>Ich sehe hier nichts besonders Neues, im Grunde genommen handelt es sich bei <code>std::move()</code> <sup>1</sup> um die gleiche Thematik wie bei <code>std::copy()</code> . Eine kluge Implementierung kann für PODs durchaus Optimierungen anwenden.</p>
<p>_____<br />
1: Überladung, die eine Iterator-Range verschiebt.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2143643</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2143643</guid><dc:creator><![CDATA[Nexus]]></dc:creator><pubDate>Sat, 12 Nov 2011 11:19:29 GMT</pubDate></item><item><title><![CDATA[Reply to std::mem_movable on Sat, 12 Nov 2011 11:40:31 GMT]]></title><description><![CDATA[<p>Nexus schrieb:</p>
<blockquote>
<p>Können <code>std::memmove()</code> und <code>std::memcpy()</code> (übrigens ohne Underscore) nicht genau dann sinvoll angewandt werden, wenn es sich um PODs handelt?</p>
</blockquote>
<p>std::string, std::vector, std::shared_ptr sind keine pods, können aber trotzdem per memcpy gemoved werden (sofern sie sich nicht intern selbst referenzieren, aber warum sollten sie).</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2143651</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2143651</guid><dc:creator><![CDATA[GorbGorb]]></dc:creator><pubDate>Sat, 12 Nov 2011 11:40:31 GMT</pubDate></item><item><title><![CDATA[Reply to std::mem_movable on Sat, 12 Nov 2011 11:54:36 GMT]]></title><description><![CDATA[<p>Das bezweifle ich. Du kannst vielleicht was zusammenhacken, aber es bleibt undefiniertes Verhalten. Schliesslich ist der Implementierung freigestellt, dir mit &quot;warum sollten sie&quot;-Aktionen den Boden unter den Füssen wegzureissen.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2143654</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2143654</guid><dc:creator><![CDATA[Nexus]]></dc:creator><pubDate>Sat, 12 Nov 2011 11:54:36 GMT</pubDate></item><item><title><![CDATA[Reply to std::mem_movable on Sat, 12 Nov 2011 12:03:58 GMT]]></title><description><![CDATA[<p>Natürlich müssen sie nicht mem_movable sein, könnten es aber trotzdem sein. Deshalb meinte ich ja, wäre es sinnvoll, einen type trait zu haben, den man spezialisieren kann.</p>
<p>So etwa:</p>
<pre><code class="language-cpp">class string
{
//...
};
template&lt;&gt;
class mem_movable&lt; string &gt;
    : public true_type
{
};
//ein std::string wird vermutlich keine Zeiger auf sich selbst besitzen
//falls er das doch tut, kann man die Spezialisierung ja weglassen
</code></pre>
]]></description><link>https://www.c-plusplus.net/forum/post/2143657</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2143657</guid><dc:creator><![CDATA[GorbGorb]]></dc:creator><pubDate>Sat, 12 Nov 2011 12:03:58 GMT</pubDate></item><item><title><![CDATA[Reply to std::mem_movable on Sat, 12 Nov 2011 14:51:13 GMT]]></title><description><![CDATA[<p>Zunächst mal solltest du schon die Optimierungen einschalten, um zu kucken, ob etwas optimiert wird. Dein Testfall erzeugt bei mir selbst mit -O1 nur noch</p>
<pre><code>Move Constructor: 3610000
memcpy: 2130000
</code></pre>
<p>Dass memcpy hier schneller ist, ist aber wenig verwunderlich, weil es stumpf weniger macht. Wie soll die Laufzeitumgebung deiner Meinung nach später auseinanderhalten, welche Objekte noch zerstört werden müssen? Stell dir vor, ich schreibe</p>
<pre><code class="language-cpp">void move_memory_maybe(mem_movable&lt;foo&gt; *dest, mem_movable&lt;foo&gt; *src, std::size_t n) {
  if(rand() % 2 == 0) std::memcpy(dest, src, n * sizeof(*dest));
}
</code></pre>
<p>...woher weiß der aufrufende Code später, wofür er Destruktoren aufrufen muss?</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2143692</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2143692</guid><dc:creator><![CDATA[seldon]]></dc:creator><pubDate>Sat, 12 Nov 2011 14:51:13 GMT</pubDate></item><item><title><![CDATA[Reply to std::mem_movable on Sat, 12 Nov 2011 15:44:20 GMT]]></title><description><![CDATA[<p>Es scheint wohl nicht ganz klar zu sein, was ich meinte...<br />
Also:<br />
Ich wünsche mir einen neuen std type trait, nämlich std::mem_movable.<br />
std::mem_movable gibt an, ob ein Typ statt per copy bzw move constructor per memcpy gemoved werden darf.<br />
Jemand der den std::vector baut dürfte z.B. bei allen Typen, für die std::mem_movable wahr ist, statt move constructor und anschließendem destructor auf den alten Objekten einfach memcpy verwenden und den alten Speicher ohne destructor freigeben.<br />
Offensichtlich ist das für POD Klassen automatisch erfüllt, bei anderen Typen würde std::mem_movable per default false ergeben.<br />
Es gibt aber auch noch viele andere Klassen, bei denen das so erfüllt ist, beispielsweise bei den meisten Versionen von std::vector und std::string.<br />
Heutige compiler können move &amp; destructor nicht optimieren, wie das von mir gepostete benchmark zeigt.<br />
Wer solche Klassen entwickelt könnte jetzt also einfach den type trait std::mem_movable für seine Klasse spezialisieren, um trotzdem klar zu machen, dass seine Klasse auf die schnellstmögliche Weise per memcpy gemoved werden darf.<br />
Vor diesem Hintergrund verstehe ich nicht, wie</p>
<p>seldon schrieb:</p>
<blockquote>
<pre><code class="language-cpp">void move_memory_maybe(mem_movable&lt;foo&gt; *dest, mem_movable&lt;foo&gt; *src, std::size_t n) {
  if(rand() % 2 == 0) std::memcpy(dest, src, n * sizeof(*dest));
}
</code></pre>
</blockquote>
<p>Sinn ergeben soll. Man erstellt keine Instanzen von type traits, die sind doch nur fürs meta programming.<br />
Wenn man move_maybe mit dem normalen move schreiben würde, wüsste der aufrufende code doch auch nicht, was er jetzt zerstören soll:</p>
<pre><code class="language-cpp">void move_maybe( T *dest , T *src )
{
    if( rand() % 2 == 0 ) new ( dest ) T( std::move( *src ) );
}
//muss auf dest jetzt der destructor aufgerufen werden?
</code></pre>
]]></description><link>https://www.c-plusplus.net/forum/post/2143708</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2143708</guid><dc:creator><![CDATA[GorbGorb]]></dc:creator><pubDate>Sat, 12 Nov 2011 15:44:20 GMT</pubDate></item><item><title><![CDATA[Reply to std::mem_movable on Sat, 12 Nov 2011 16:12:45 GMT]]></title><description><![CDATA[<p>GorbGorb schrieb:</p>
<blockquote>
<p>Es scheint wohl nicht ganz klar zu sein, was ich meinte...<br />
Also:<br />
Ich wünsche mir einen neuen std type trait, nämlich std::mem_movable.<br />
std::mem_movable gibt an, ob ein Typ statt per copy bzw move constructor per memcpy gemoved werden darf.<br />
Jemand der den std::vector baut dürfte z.B. bei allen Typen, für die std::mem_movable wahr ist, statt move constructor und anschließendem destructor auf den alten Objekten einfach memcpy verwenden und den alten Speicher ohne destructor freigeben.<br />
Offensichtlich ist das für POD Klassen automatisch erfüllt, bei anderen Typen würde std::mem_movable per default false ergeben.<br />
Es gibt aber auch noch viele andere Klassen, bei denen das so erfüllt ist, beispielsweise bei den meisten Versionen von std::vector und std::string.<br />
Heutige compiler können move &amp; destructor nicht optimieren, wie das von mir gepostete benchmark zeigt.<br />
Wer solche Klassen entwickelt könnte jetzt also einfach den type trait std::mem_movable für seine Klasse spezialisieren, um trotzdem klar zu machen, dass seine Klasse auf die schnellstmögliche Weise per memcpy gemoved werden darf.<br />
Vor diesem Hintergrund verstehe ich nicht, wie</p>
<p>seldon schrieb:</p>
<blockquote>
<pre><code class="language-cpp">void move_memory_maybe(mem_movable&lt;foo&gt; *dest, mem_movable&lt;foo&gt; *src, std::size_t n) {
  if(rand() % 2 == 0) std::memcpy(dest, src, n * sizeof(*dest));
}
</code></pre>
</blockquote>
<p>Sinn ergeben soll. Man erstellt keine Instanzen von type traits, die sind doch nur fürs meta programming.<br />
Wenn man move_maybe mit dem normalen move schreiben würde, wüsste der aufrufende code doch auch nicht, was er jetzt zerstören soll:</p>
<pre><code class="language-cpp">void move_maybe( T *dest , T *src )
{
    if( rand() % 2 == 0 ) new ( dest ) T( std::move( *src ) );
}
//muss auf dest jetzt der destructor aufgerufen werden?
</code></pre>
</blockquote>
<p>Objekte, die nicht trivial kopiert werden können, per memcpy/memmove zu kopieren, führt zu undefiniertem Verhalten (genauer: das Kopieren selbst ist unproblematisch, aber an der Zieladresse entstehen keine Objekte des entsprechenden Typs, und dann darauf zugreifen zu wollen, als ob entsprechende Objekte da wären führt zu UB, i.d.R. über 3.10/10).<br />
Es wäre denkbar, ein Prädikat zu haben, dass aussagt, ob die Ausführung eines nicht-trivialen Destruktors unterbleiben darf, falls irgendwie eine flache Kopie erstellt wurde. Ohne eine entsprechend universell einsatzbare und schnelle Kopierroutine (und memcpy ist eben genau das nicht), ist es nicht besonders nützlich.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2143711</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2143711</guid><dc:creator><![CDATA[camper]]></dc:creator><pubDate>Sat, 12 Nov 2011 16:12:45 GMT</pubDate></item><item><title><![CDATA[Reply to std::mem_movable on Sun, 13 Nov 2011 01:40:09 GMT]]></title><description><![CDATA[<p>GorbGorb schrieb:</p>
<blockquote>
<p>Wenn man move_maybe mit dem normalen move schreiben würde, wüsste der aufrufende code doch auch nicht, was er jetzt zerstören soll:</p>
<pre><code class="language-cpp">void move_maybe( T *dest , T *src )
{
    if( rand() % 2 == 0 ) new ( dest ) T( std::move( *src ) );
}
//muss auf dest jetzt der destructor aufgerufen werden?
</code></pre>
</blockquote>
<p>Ich wollte eigentlich mehr auf src hinaus. Ein Move-Konstruktor muss ja nicht nur den Inhalt des Quellobjektes kopieren, sondern auch das alte invalidieren. Für std::vector in gccs libstdc++ sieht das etwa so aus (in einer privaten Basisklasse):</p>
<pre><code class="language-cpp">_Vector_base(_Vector_base&amp;&amp; __x)
      : _M_impl(__x._M_get_Tp_allocator())
      {
        this-&gt;_M_impl._M_start = __x._M_impl._M_start;
        this-&gt;_M_impl._M_finish = __x._M_impl._M_finish;
        this-&gt;_M_impl._M_end_of_storage = __x._M_impl._M_end_of_storage;
        __x._M_impl._M_start = 0;
        __x._M_impl._M_finish = 0;
        __x._M_impl._M_end_of_storage = 0;
      }
</code></pre>
<p>Der Destruktor wird dann für alle Objekte nach wie vor aufgerufen, macht aber für die geleerten (praktisch) nichts. Vor diesem Hintergrund ist es wenig verwunderlich, dass dein Benchmark einen Geschwindigkeitsvorteil für memcpy heraushaut, weil memcpy ja stumpf weniger macht. Ich sehe nicht, wie bei deinem Ansatz sichergestellt werden kann, dass die Laufzeitumgebung bewegte von unbewegten Objekten unterscheiden kann.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2143832</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2143832</guid><dc:creator><![CDATA[seldon]]></dc:creator><pubDate>Sun, 13 Nov 2011 01:40:09 GMT</pubDate></item><item><title><![CDATA[Reply to std::mem_movable on Sat, 26 Nov 2011 16:31:36 GMT]]></title><description><![CDATA[<p>camper schrieb:</p>
<blockquote>
<p>Objekte, die nicht trivial kopiert werden können, per memcpy/memmove zu kopieren, führt zu undefiniertem Verhalten (genauer: das Kopieren selbst ist unproblematisch, aber an der Zieladresse entstehen keine Objekte des entsprechenden Typs, und dann darauf zugreifen zu wollen, als ob entsprechende Objekte da wären führt zu UB, i.d.R. über 3.10/10).</p>
</blockquote>
<p>Schade, dann bräuchte ein solches feature also Änderungen am c++ core (und wohl nicht unerhebliche).</p>
<blockquote>
<p>Es wäre denkbar, ein Prädikat zu haben, dass aussagt, ob die Ausführung eines nicht-trivialen Destruktors unterbleiben darf, falls irgendwie eine flache Kopie erstellt wurde. Ohne eine entsprechend universell einsatzbare und schnelle Kopierroutine (und memcpy ist eben genau das nicht), ist es nicht besonders nützlich.</p>
</blockquote>
<p>Mir ist das Ganze gekommen, als ich über einen move-Konstruktor für shared_ptr nachgedachte habe. Mit mem_movable könnte man sich hier ein <code>if( ptr )</code> bzw. ein Zugriff auf ein std::atomic beim moven sparen (beides nicht gerade billig).<br />
Außerdem ist das halt etwas, das idiomatisches c++ langsamer als c macht, was ich irgendwie unbefriedigend finde.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2149244</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2149244</guid><dc:creator><![CDATA[GorbGorb]]></dc:creator><pubDate>Sat, 26 Nov 2011 16:31:36 GMT</pubDate></item><item><title><![CDATA[Reply to std::mem_movable on Sat, 26 Nov 2011 21:26:23 GMT]]></title><description><![CDATA[<p>GorbGorb schrieb:</p>
<blockquote>
<p>camper schrieb:</p>
<blockquote>
<p>Objekte, die nicht trivial kopiert werden können, per memcpy/memmove zu kopieren, führt zu undefiniertem Verhalten (genauer: das Kopieren selbst ist unproblematisch, aber an der Zieladresse entstehen keine Objekte des entsprechenden Typs, und dann darauf zugreifen zu wollen, als ob entsprechende Objekte da wären führt zu UB, i.d.R. über 3.10/10).</p>
</blockquote>
<p>Schade, dann bräuchte ein solches feature also Änderungen am c++ core (und wohl nicht unerhebliche).</p>
</blockquote>
<p>Ich gehe sogar soweit zu behaupten dass so ein Feature nicht konsistent in die Sprache eingeführt werden könnte.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2149379</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2149379</guid><dc:creator><![CDATA[pumuckl]]></dc:creator><pubDate>Sat, 26 Nov 2011 21:26:23 GMT</pubDate></item><item><title><![CDATA[Reply to std::mem_movable on Sun, 27 Nov 2011 01:02:40 GMT]]></title><description><![CDATA[<p>pumuckl schrieb:</p>
<blockquote>
<p>Ich gehe sogar soweit zu behaupten dass so ein Feature nicht konsistent in die Sprache eingeführt werden könnte.</p>
</blockquote>
<p>c++ und Konsistenz... aber das ist ein anderes Thema.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2149423</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2149423</guid><dc:creator><![CDATA[GorbGorb]]></dc:creator><pubDate>Sun, 27 Nov 2011 01:02:40 GMT</pubDate></item><item><title><![CDATA[Reply to std::mem_movable on Sun, 27 Nov 2011 10:26:05 GMT]]></title><description><![CDATA[<p>GorbGorb schrieb:</p>
<blockquote>
<p>c++ und Konsistenz... aber das ist ein anderes Thema.</p>
</blockquote>
<p>Beispiele?</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2149466</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2149466</guid><dc:creator><![CDATA[otze]]></dc:creator><pubDate>Sun, 27 Nov 2011 10:26:05 GMT</pubDate></item><item><title><![CDATA[Reply to std::mem_movable on Sun, 27 Nov 2011 10:52:52 GMT]]></title><description><![CDATA[<p>otze schrieb:</p>
<blockquote>
<p>GorbGorb schrieb:</p>
<blockquote>
<p>c++ und Konsistenz... aber das ist ein anderes Thema.</p>
</blockquote>
<p>Beispiele?</p>
</blockquote>
<p>Typenme z.B.</p>
<p>(Von Effective C++ kopiert)</p>
<pre><code class="language-cpp">template&lt;typename T&gt;
class Derived : public Base&lt;T&gt;::Nested { //typename nicht zulässig
public:
  explicit Derived(int x)
    : Base&lt;T&gt;::Nested(x) {} // typename nicht zulässig

  // ...
  void some_member_function() {
    //...
    typename Base&lt;T&gt;::Nested temp; // typename erforderlich
    //...
  }
};
</code></pre>
<p>Auch wenn einem die Regeln klar sind, warum man an den verschiedenen Stellen typename braucht bzw. es nicht zulässig ist, so ist es dennoch inkonsistent. Man hätte typename wenigstens dann, wenn es unnötig ist, trotzdem zulassen können.</p>
<p>Man muss ja auch bei geerbten virtuellen Funktionen das <code>virtual</code> nicht mehr extra hinschreiben, aber es ist kein Fehler, wenn man es trotzdem tut.</p>
<pre><code class="language-cpp">class Base {
  virtual foo();
  virtual bar();
};

class Derived {
  foo(){ // implizit virtual
    // ... 
  }
  virtual bar(){ // virtual zwar unnötig, aber dennoch kein Fehler
    // ...
  }
};
</code></pre>
]]></description><link>https://www.c-plusplus.net/forum/post/2149482</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2149482</guid><dc:creator><![CDATA[bmario_]]></dc:creator><pubDate>Sun, 27 Nov 2011 10:52:52 GMT</pubDate></item><item><title><![CDATA[Reply to std::mem_movable on Sun, 27 Nov 2011 10:54:28 GMT]]></title><description><![CDATA[<p>Mist, Derived im zweiten Beispiel sollte natürlich von Base ableiten!</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2149483</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2149483</guid><dc:creator><![CDATA[bmario_]]></dc:creator><pubDate>Sun, 27 Nov 2011 10:54:28 GMT</pubDate></item><item><title><![CDATA[Reply to std::mem_movable on Sun, 27 Nov 2011 11:55:21 GMT]]></title><description><![CDATA[<p>Zuerst mal wäre da die Erbsünde c zu nennen, Präprozessor, Ellipsen, etc.<br />
Dann kommen noch ein paar Sachen von c++ dazu:</p>
<ul>
<li>don't pay what you don't use wird verletzt:<br />
- rtti<br />
- exceptions (war es nicht so dass die compiler dann nicht so gut optimieren<br />
können? wobei exceptions ein Programm auch schneller machen können, hier gibt es wohl keinen Königsweg)</li>
<li>die Standardbibliothek ist mit der Sprache verwurstelt: typeid, dynamic_cast und sizeof</li>
<li>private Member sieht man auch in einer abgeleiteten Klasse:</li>
</ul>
<pre><code class="language-cpp">class A
{
};
class Base
{
    class A
    {
    };
};
class Derived
    : public Base
{
    A a;
};
</code></pre>
<ul>
<li>template Syntax, bin ja grade erst wieder auf die Schnauze geflogen, weil sowas möglich ist:</li>
</ul>
<pre><code class="language-cpp">template&lt; template&lt; class &gt; class Template &gt;
class A
{
};
template&lt; class Type &gt;
class B
{
};

template&lt; class Type &gt;
class C
{
	A&lt; C &gt; a;  //C als class template
	B&lt; C &gt; b;  //C als class
};
</code></pre>
]]></description><link>https://www.c-plusplus.net/forum/post/2149513</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2149513</guid><dc:creator><![CDATA[GorbGorb]]></dc:creator><pubDate>Sun, 27 Nov 2011 11:55:21 GMT</pubDate></item><item><title><![CDATA[Reply to std::mem_movable on Sun, 27 Nov 2011 12:13:43 GMT]]></title><description><![CDATA[<p>bmario_ schrieb:</p>
<blockquote>
<p>Auch wenn einem die Regeln klar sind, warum man an den verschiedenen Stellen typename braucht bzw. es nicht zulässig ist, so ist es dennoch inkonsistent.</p>
</blockquote>
<p>Unintuitiv, aber nicht inkonsistent. Inkonsistenz würde bedeuten, dass der Standard sich selbst widerspricht.</p>
<p>GorbGorb schrieb:</p>
<blockquote>
<p>Zuerst mal wäre da die Erbsünde c zu nennen, Präprozessor, Ellipsen, etc.</p>
</blockquote>
<p>Was ist da inkonsistent?</p>
<blockquote>
<p>don't pay what you don't use wird verletzt:<br />
- rtti<br />
- exceptions (war es nicht so dass die compiler dann nicht so gut optimieren<br />
können? wobei exceptions ein Programm auch schneller machen können, hier gibt es wohl keinen Königsweg)</p>
</blockquote>
<p>Wo wird da was verletzt? Für Klassen ohne virtuelle Funktionen gibts auch kein RTTI. Wenn man keine Exceptions benutzt, verlangt der Standard auch keinen Overhead dafür. (Was die Compiler draus machen ist was anderes)</p>
<blockquote>
<p>[*] die Standardbibliothek ist mit der Sprache verwurstelt: typeid, dynamic_cast und sizeof</p>
</blockquote>
<p>Mal abgesehen davon dass weder dynamic_cast noch sizeof irgendwas mit der Standardbibliothek zu tun haben: Was macht den Standard in sich inkonsistent, wenn zwei seiner Features (typeid-Operator und type_info Klasse) voneinander abhängig sind? Beide sind Teil des Standards, genauso wie Klassen und Memberfunktionen - letztere würden ohne erstere auch keinen Sinn machen.</p>
<blockquote>
<p>[*] private Member sieht man auch in einer abgeleiteten Klasse:</p>
<pre><code class="language-cpp">class A
{
};
class Base
{
    class A
    {
    };
};
class Derived
    : public Base
{
    A a;
};
</code></pre>
</blockquote>
<p>Da bist du einem Irrtum aufgesessen. Derived sieht nur ::A, nicht Base::A.</p>
<blockquote>
<p>[*] template Syntax, bin ja grade erst wieder auf die Schnauze geflogen, weil sowas möglich ist:</p>
<pre><code class="language-cpp">template&lt; template&lt; class &gt; class Template &gt;
class A
{
};
template&lt; class Type &gt;
class B
{
};

template&lt; class Type &gt;
class C
{
	A&lt; C &gt; a;  //C als class template
	B&lt; C &gt; b;  //C als class
};
</code></pre>
</blockquote>
<p>Und? Wo ist die Inkonsistenz? Dass du mit den Regeln auf dem Kriegsfuß stehst und Probleme damit hast, bedeutet doch nicht, dass der Standard inkonsistent ist.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2149527</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2149527</guid><dc:creator><![CDATA[pumuckl]]></dc:creator><pubDate>Sun, 27 Nov 2011 12:13:43 GMT</pubDate></item><item><title><![CDATA[Reply to std::mem_movable on Sun, 27 Nov 2011 12:22:21 GMT]]></title><description><![CDATA[<p>Zu GorbGorbs Beitrag wollte ich auch gerade was schreiben, pumuckl hat aber schon alles gesagt <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f642.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--slightly_smiling_face"
      title=":)"
      alt="🙂"
    /></p>
<p>Wie sieht es aber mit dem <code>typename</code> aus, warum genau ist das bei Vererbungs- und Initialisierungsliste verboten? Ich würde hier übrigens auch von Inkonsistenz sprechen, dazu muss kein Widerspruch vorhanden sein.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2149528</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2149528</guid><dc:creator><![CDATA[Nexus]]></dc:creator><pubDate>Sun, 27 Nov 2011 12:22:21 GMT</pubDate></item><item><title><![CDATA[Reply to std::mem_movable on Sun, 27 Nov 2011 12:36:47 GMT]]></title><description><![CDATA[<p>GorbGorb schrieb:</p>
<blockquote>
<p>Zuerst mal wäre da die Erbsünde c zu nennen, Präprozessor, Ellipsen, etc.</p>
</blockquote>
<p>Mit beidem kann man tolle Sachen machen. Den Präprozessor, um Schreibarbeit zu sparen, Ellipsen für TMP.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2149536</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2149536</guid><dc:creator><![CDATA[314159265358979]]></dc:creator><pubDate>Sun, 27 Nov 2011 12:36:47 GMT</pubDate></item><item><title><![CDATA[Reply to std::mem_movable on Sun, 27 Nov 2011 12:40:10 GMT]]></title><description><![CDATA[<p>Ich denke man sollte inkonsistent hier schon als unintuitiv zu den sonstigen Regeln sehen, dass der Standard selbst nicht zweideutig ist, ist glaube ich jedem hier klar.</p>
<p><a class="plugin-mentions-user plugin-mentions-a" href="https://www.c-plusplus.net/forum/uid/1053">@virtual</a> -&gt; Hmja, man sollte virtual wohl eher zur Pflicht machen, anstatt es zu verbieten.<br />
@Don't pay<br />
1. @RTTI -&gt; Hm.. man zahlt dafür wenn man es nicht nutzt? Das ist mir neu.<br />
2. @exceptions -&gt; Ohne try/catch hast du keine Nachteile. Und try/catch zu nutzen ohne etwas zu werfen ist irgendwie.. suboptimal.<br />
@die Standardbibliothek ist mit der Sprache verwurstelt.. -&gt; <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f615.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--confused_face"
      title=":confused:"
      alt="😕"
    /><br />
<a class="plugin-mentions-user plugin-mentions-a" href="https://www.c-plusplus.net/forum/uid/8298">@template</a> -&gt; Na ja. Das würde ich in der Tat als etwas inkonsistent ansehen, aber es ist einfach zu hilfreich um es abzuschaffen.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2149538</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2149538</guid><dc:creator><![CDATA[cooky451]]></dc:creator><pubDate>Sun, 27 Nov 2011 12:40:10 GMT</pubDate></item><item><title><![CDATA[Reply to std::mem_movable on Sun, 27 Nov 2011 12:42:43 GMT]]></title><description><![CDATA[<p>pumuckl schrieb:</p>
<blockquote>
<p>bmario_ schrieb:</p>
<blockquote>
<p>Auch wenn einem die Regeln klar sind, warum man an den verschiedenen Stellen typename braucht bzw. es nicht zulässig ist, so ist es dennoch inkonsistent.</p>
</blockquote>
<p>Unintuitiv, aber nicht inkonsistent. Inkonsistenz würde bedeuten, dass der Standard sich selbst widerspricht.</p>
</blockquote>
<p>Inkonsistent in dem Sinne, dass an vielen Stellen in C++ implizit Festlegungen gelten, aber es kein Fehler ist, diese dennoch explizit aufzuschreiben.<br />
Beispiele dafür:<br />
- in der Klassendefinition definierte Funktionen sind implizit inline, aber es ist kein Fehler, ein inline explizit hinzuschreiben.<br />
- definiert man einen der großen Drei nicht, wird vom Kompiler implizit einer generiert, aber es ist kein Fehler, einen semantisch äquivalenten explizit zu definieren.<br />
- beim Ableiten einer Klasse wird ohne Schlüsselwort implizit angenommen, dass die Ableitung <code>public</code> ist, aber es ist kein Fehler dies explizit hinzuschreiben<br />
- geerbte virtuelle Funktionen sind implizit virtuell, aber es ist kein Fehler, dies explizit hinzuschreiben.</p>
<p><strong>vs.</strong><br />
- An Stellen, wo Typen erwartet werden, werden geschachtelte abhängige Namen implizit als Typen angenommen, <strong>ABER</strong> es ist ein Fehler, dies explizit hinzuschreiben<br />
- Voll qualifizierte geschachtelte Namen werden implizit als Typen erkannt, aber es ist ein Fehler, dies explizit hinzuschreiben.</p>
<p>Das würde ich schon inkonsistent nennen, aber man kann natürlich jetzt darüber diskutieren, was man als inkonsistent ansieht <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f921.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--clown_face"
      title=":clown:"
      alt="🤡"
    /></p>
]]></description><link>https://www.c-plusplus.net/forum/post/2149540</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2149540</guid><dc:creator><![CDATA[bmario_]]></dc:creator><pubDate>Sun, 27 Nov 2011 12:42:43 GMT</pubDate></item></channel></rss>