<?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::vector::push_back: mit VS. ohne vorausgehendem reserve]]></title><description><![CDATA[<p>Guten Abend,<br />
ich dachte immer, wenn ein <code>vector</code> eine große Menge an Daten zu verwalten hat, macht man vorausgehend eine Schätzung mit <code>reserve</code> , um wie viele Daten es sich ca. handeln könnte, da ein push_back mit Speicherallokation langsamer ist als ohne. Ich habe nun mal einen <code>vector</code> mit 200 Mio. Ganzzahlen abgelegt und war erstaunt, dass <code>reserve</code> so gut wie gar keine Rolle spielt.</p>
<p>Mit <code>reserve</code> :</p>
<pre><code class="language-cpp">#include &lt;chrono&gt;
#include &lt;iostream&gt;
#include &lt;string&gt;
#include &lt;vector&gt;
using namespace std;

class stopwatch
{
	private:
    	chrono::time_point&lt;chrono::high_resolution_clock&gt; start;
    	chrono::time_point&lt;chrono::high_resolution_clock&gt; stop;
	public:
    	void start_watch()
    	{
        	start = chrono::high_resolution_clock::now();
    	}
    	void stop_watch()
    	{
        	stop = chrono::high_resolution_clock::now();
    	}
		unsigned elapsed() const
    	{
        	return chrono::duration_cast&lt;std::chrono::milliseconds&gt;(stop-start).count();
    	}
};

int main()
{
	stopwatch watch;
	vector&lt;unsigned&gt; vec;

	vec.reserve(100000000); // 100.000.000

	watch.start_watch();
	for(unsigned i=0; i&lt;100000000; ++i)
	{
		vec.push_back(i);
	}
	watch.stop_watch();
	cout &lt;&lt; &quot;elapsed = &quot; &lt;&lt; watch.elapsed();
}
</code></pre>
<p>GCC 4.6.1 32-bit:<br />
Ohne Optimierung ---&gt; 1052ms<br />
-O1 ---&gt; 308ms</p>
<p>Ohne <code>reserve</code> :</p>
<pre><code class="language-cpp">int main()
{
	stopwatch watch;
	vector&lt;unsigned&gt; vec;

	watch.start_watch();
	for(unsigned i=0; i&lt;100000000; ++i)
	{
		vec.push_back(i);
	}
	watch.stop_watch();
	cout &lt;&lt; &quot;elapsed = &quot; &lt;&lt; watch.elapsed();
}
</code></pre>
<p>GCC 4.6.1 32-bit:<br />
Ohne Optimierung ---&gt; 1226ms<br />
-O1 ---&gt; 464ms</p>
<p>Ohne Optimierung ist es mit <code>reserve</code> nur ca. 200ms schneller und mit gar nur ca. 150ms.<br />
Jetzt frage ich mich, wann ich nun eigentlich <code>reserve</code> einsetzen sollte. Wie macht ihr das? Wann benutzt ihr <code>reserve</code> ?</p>
<p>Danke im Voraus.</p>
]]></description><link>https://www.c-plusplus.net/forum/topic/304245/std-vector-push_back-mit-vs-ohne-vorausgehendem-reserve</link><generator>RSS for Node</generator><lastBuildDate>Sun, 09 Aug 2026 21:02:32 GMT</lastBuildDate><atom:link href="https://www.c-plusplus.net/forum/topic/304245.rss" rel="self" type="application/rss+xml"/><pubDate>Fri, 01 Jun 2012 18:59:14 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to std::vector::push_back: mit VS. ohne vorausgehendem reserve on Fri, 01 Jun 2012 18:59:14 GMT]]></title><description><![CDATA[<p>Guten Abend,<br />
ich dachte immer, wenn ein <code>vector</code> eine große Menge an Daten zu verwalten hat, macht man vorausgehend eine Schätzung mit <code>reserve</code> , um wie viele Daten es sich ca. handeln könnte, da ein push_back mit Speicherallokation langsamer ist als ohne. Ich habe nun mal einen <code>vector</code> mit 200 Mio. Ganzzahlen abgelegt und war erstaunt, dass <code>reserve</code> so gut wie gar keine Rolle spielt.</p>
<p>Mit <code>reserve</code> :</p>
<pre><code class="language-cpp">#include &lt;chrono&gt;
#include &lt;iostream&gt;
#include &lt;string&gt;
#include &lt;vector&gt;
using namespace std;

class stopwatch
{
	private:
    	chrono::time_point&lt;chrono::high_resolution_clock&gt; start;
    	chrono::time_point&lt;chrono::high_resolution_clock&gt; stop;
	public:
    	void start_watch()
    	{
        	start = chrono::high_resolution_clock::now();
    	}
    	void stop_watch()
    	{
        	stop = chrono::high_resolution_clock::now();
    	}
		unsigned elapsed() const
    	{
        	return chrono::duration_cast&lt;std::chrono::milliseconds&gt;(stop-start).count();
    	}
};

int main()
{
	stopwatch watch;
	vector&lt;unsigned&gt; vec;

	vec.reserve(100000000); // 100.000.000

	watch.start_watch();
	for(unsigned i=0; i&lt;100000000; ++i)
	{
		vec.push_back(i);
	}
	watch.stop_watch();
	cout &lt;&lt; &quot;elapsed = &quot; &lt;&lt; watch.elapsed();
}
</code></pre>
<p>GCC 4.6.1 32-bit:<br />
Ohne Optimierung ---&gt; 1052ms<br />
-O1 ---&gt; 308ms</p>
<p>Ohne <code>reserve</code> :</p>
<pre><code class="language-cpp">int main()
{
	stopwatch watch;
	vector&lt;unsigned&gt; vec;

	watch.start_watch();
	for(unsigned i=0; i&lt;100000000; ++i)
	{
		vec.push_back(i);
	}
	watch.stop_watch();
	cout &lt;&lt; &quot;elapsed = &quot; &lt;&lt; watch.elapsed();
}
</code></pre>
<p>GCC 4.6.1 32-bit:<br />
Ohne Optimierung ---&gt; 1226ms<br />
-O1 ---&gt; 464ms</p>
<p>Ohne Optimierung ist es mit <code>reserve</code> nur ca. 200ms schneller und mit gar nur ca. 150ms.<br />
Jetzt frage ich mich, wann ich nun eigentlich <code>reserve</code> einsetzen sollte. Wie macht ihr das? Wann benutzt ihr <code>reserve</code> ?</p>
<p>Danke im Voraus.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2218266</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2218266</guid><dc:creator><![CDATA[[[global:guest]]]]></dc:creator><pubDate>Fri, 01 Jun 2012 18:59:14 GMT</pubDate></item><item><title><![CDATA[Reply to std::vector::push_back: mit VS. ohne vorausgehendem reserve on Fri, 01 Jun 2012 19:34:07 GMT]]></title><description><![CDATA[<p>Was heisst &quot;so gut wie gar keine Rolle&quot;?</p>
<p>464ms dauert 50% länger als 308ms...</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2218269</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2218269</guid><dc:creator><![CDATA[Nexus]]></dc:creator><pubDate>Fri, 01 Jun 2012 19:34:07 GMT</pubDate></item><item><title><![CDATA[Reply to std::vector::push_back: mit VS. ohne vorausgehendem reserve on Fri, 01 Jun 2012 19:44:46 GMT]]></title><description><![CDATA[<p>Stroustrup hat selbst was darüber geschrieben:<br />
<a href="http://www2.research.att.com/~bs/bs_faq2.html" rel="nofollow">http://www2.research.att.com/~bs/bs_faq2.html</a><br />
(Strg-f nach reserve)</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2218270</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2218270</guid><dc:creator><![CDATA[IrgendeinName]]></dc:creator><pubDate>Fri, 01 Jun 2012 19:44:46 GMT</pubDate></item><item><title><![CDATA[Reply to std::vector::push_back: mit VS. ohne vorausgehendem reserve on Fri, 01 Jun 2012 21:00:47 GMT]]></title><description><![CDATA[<p>Hängt wohl auch davon ab, was gespeichert wird. ein std::vector<a href="std::string" rel="nofollow">std::string</a> ist da wohl deutlich heftiger bei Reallocations als ein std::vector&lt;int&gt;</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2218304</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2218304</guid><dc:creator><![CDATA[Ethon]]></dc:creator><pubDate>Fri, 01 Jun 2012 21:00:47 GMT</pubDate></item><item><title><![CDATA[Reply to std::vector::push_back: mit VS. ohne vorausgehendem reserve on Fri, 01 Jun 2012 21:31:34 GMT]]></title><description><![CDATA[<p>Ethon schrieb:</p>
<blockquote>
<p>Hängt wohl auch davon ab, was gespeichert wird. ein std::vector<a href="std::string" rel="nofollow">std::string</a> ist da wohl deutlich heftiger bei Reallocations als ein std::vector&lt;int&gt;</p>
</blockquote>
<p>Eben nicht, Stichwort: Move constructor. <code>string</code> ist billig zu bewegen, aber teuer initial zu konstruieren. <code>int</code> macht da keinen Unterschied.</p>
<p>Die ganzen Speicheranforderungen werden den Unterschied undeutlicher machen (heißt: kleiner als 50%).</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2218316</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2218316</guid><dc:creator><![CDATA[TyRoXx]]></dc:creator><pubDate>Fri, 01 Jun 2012 21:31:34 GMT</pubDate></item><item><title><![CDATA[Reply to std::vector::push_back: mit VS. ohne vorausgehendem reserve on Sat, 02 Jun 2012 04:32:55 GMT]]></title><description><![CDATA[<p>TyRoXx schrieb:</p>
<blockquote>
<p>Eben nicht, Stichwort: Move constructor</p>
</blockquote>
<p>In C++11</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2218357</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2218357</guid><dc:creator><![CDATA[C++03er]]></dc:creator><pubDate>Sat, 02 Jun 2012 04:32:55 GMT</pubDate></item><item><title><![CDATA[Reply to std::vector::push_back: mit VS. ohne vorausgehendem reserve on Sat, 02 Jun 2012 07:53:36 GMT]]></title><description><![CDATA[<p>C++03er schrieb:</p>
<blockquote>
<p>TyRoXx schrieb:</p>
<blockquote>
<p>Eben nicht, Stichwort: Move constructor</p>
</blockquote>
<p>In C++11</p>
</blockquote>
<p>Jain. Soweit ich weiß, war das schon vorher bei MSVC optimiert. Die haben da irgendwelche Traits, die einem sagen, ob ein Objekt x des Typs T per</p>
<pre><code class="language-cpp">T x = ...;
T y;
swap(x,y);
</code></pre>
<p>fix nach y &quot;movebar&quot; ist, ohne dass Ausnahmen fliegen (swaptimization). Und in so einem Falle wählt ihre std::vector-Implementierung für ihre eigenen Typen, die genau das können (std::string, std::vector, ...), eine entsprechende &quot;grow&quot;-Funktion aus, die das ausnutzt.</p>
<p>Aber für selbstdefinierte Klassen mit aufwändigeren Kopier-Konstruktoren und ohne Move-Konstruktoren, wird es sicherlich einen größeren Unterschied machen.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2218371</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2218371</guid><dc:creator><![CDATA[krümelkacker]]></dc:creator><pubDate>Sat, 02 Jun 2012 07:53:36 GMT</pubDate></item><item><title><![CDATA[Reply to std::vector::push_back: mit VS. ohne vorausgehendem reserve on Sat, 02 Jun 2012 12:18:00 GMT]]></title><description><![CDATA[<p>Wieso nicht einfach per memcpy in den anderen Speicherbereich kopieren, ohne Allocator::destroy auf die alten Daten loszulassen? Ist ja nicht so als würde std::vector mit new/delete herumhantieren, Konstruktoren und Destruktoren werden alle explizit aufgerufen.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2218465</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2218465</guid><dc:creator><![CDATA[Ethon]]></dc:creator><pubDate>Sat, 02 Jun 2012 12:18:00 GMT</pubDate></item><item><title><![CDATA[Reply to std::vector::push_back: mit VS. ohne vorausgehendem reserve on Sat, 02 Jun 2012 12:48:25 GMT]]></title><description><![CDATA[<p>Ethon schrieb:</p>
<blockquote>
<p>Wieso nicht einfach per memcpy in den anderen Speicherbereich kopieren, ohne Allocator::destroy auf die alten Daten loszulassen?</p>
</blockquote>
<p>Weil du vielleicht keine plain Data Objekte hast, sondern komplexe Objekte die Zeiger auf andere Objekte haben. Und wenn du da einfach mal so die Adressen der Objekte aenderst dann kommen Bugs zustande die unmoeglich zu finden sind.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2218478</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2218478</guid><dc:creator><![CDATA[Shade Of Mine]]></dc:creator><pubDate>Sat, 02 Jun 2012 12:48:25 GMT</pubDate></item><item><title><![CDATA[Reply to std::vector::push_back: mit VS. ohne vorausgehendem reserve on Sat, 02 Jun 2012 12:57:02 GMT]]></title><description><![CDATA[<p>Fällt dir ein Szenario ein, in dem ein Objekt sich bei einem Move-Vorgang verändern würde?</p>
<p>Mit std::string oä. wäre memcpy auf jeden Fall kein Problem.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2218480</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2218480</guid><dc:creator><![CDATA[Ethon]]></dc:creator><pubDate>Sat, 02 Jun 2012 12:57:02 GMT</pubDate></item><item><title><![CDATA[Reply to std::vector::push_back: mit VS. ohne vorausgehendem reserve on Sat, 02 Jun 2012 13:34:54 GMT]]></title><description><![CDATA[<p>Ethon schrieb:</p>
<blockquote>
<p>Wieso nicht einfach per memcpy in den anderen Speicherbereich kopieren, ohne Allocator::destroy auf die alten Daten loszulassen? Ist ja nicht so als würde std::vector mit new/delete herumhantieren, Konstruktoren und Destruktoren werden alle explizit aufgerufen.</p>
</blockquote>
<pre><code class="language-cpp">using namespace std;

static void memcpyStrings(string *from, string *to, size_t count)
{
	memcpy(to, from, count * sizeof(*to));
}

static void moveStrings(string *from, string *to, size_t count)
{
	for (size_t i = 0; i &lt; count; ++i)
	{
		//Kopiert 'from' nach 'to' und setzt 'from' in einen Nullzustand.
		//Das Kopieren könnte vom Compiler mit memcpy() optimiert werden.
		//Das Setzen in den Nullzustand kann weggelassen werden, wenn
		//der Optimierer die zweite Schleife berücksichtigt.
		new (to + i) string(std::move(from[i]));
	}
	for (string *i = from + count - 1; i &gt;= from; --i)
	{
		//'from' wird zerstört, was aber im Nullzustand nichts bewirkt.
		//Der Optimierer könnte erkennen, dass der Move-Konstruktor aus
		//der vorherigen Schleife alle Objekte in den Nullzustand versetzt,
		//sodass die zweite Schleife gar nichts tut.
		//Da das Lesen aus zerstörten Objekten undefiniertes Verhalten ist,
		//können alle finalen Schreibvorgänge ohne Seiteneffekte in den Objekten
		//weggelassen werden. Konkret: Das Versetzen in den Nullzustand findet
		//nicht statt, die Zerstörung wird sozusagen zur Compile-Zeit erledigt.
		(i)-&gt;~string();
	}

	//Zusammengefasst: Ein schlauer Optimierer kann das alles durch
	//	memcpy(to, from, count * sizeof(*to));
	//ersetzen und ist damit standardkonform.
}
</code></pre>
<p>Man könnte diese Optimierung auf der Ebene der Standardbibliothek implementieren, indem man abhängig von gewissen Eigenschaften von <code>T</code> einfach <code>memcpy</code> verwendet. Bei vordefinierten Typen wie <code>std::string</code> könnte das funktionieren.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2218484</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2218484</guid><dc:creator><![CDATA[TyRoXx]]></dc:creator><pubDate>Sat, 02 Jun 2012 13:34:54 GMT</pubDate></item><item><title><![CDATA[Reply to std::vector::push_back: mit VS. ohne vorausgehendem reserve on Sat, 02 Jun 2012 13:45:55 GMT]]></title><description><![CDATA[<p>Ethon schrieb:</p>
<blockquote>
<p>Wieso nicht einfach per memcpy in den anderen Speicherbereich kopieren, ohne Allocator::destroy auf die alten Daten loszulassen?</p>
</blockquote>
<p>Das geht problemlos bei PODs (Da wirds auch so gemnacht). Außerdem gehts bei Klassen, die gewisse Voraussetzungen haben - im wesentlichen alles, was vergleichsweise simple noexcept move-konstruktoren hat, wo bei den Kopien keine anderen Objekte benachrichtigt werden müssen usw. Nach dem Optimizer mit reordering und Zusammenfassen der einzelnen Kopien von hintereinander liegendem Speicher wird da im Grunde was ähnlich performantes rauskommen wie memcpy.</p>
<p>Es geht aber eben nicht immer, und deshalb kannn mans nicht einfach allgemein so machen sondern muss die Spezialifälle abprüfen und eine passende Behandlung nehmen.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2218490</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2218490</guid><dc:creator><![CDATA[pumuckl]]></dc:creator><pubDate>Sat, 02 Jun 2012 13:45:55 GMT</pubDate></item></channel></rss>