{"id":5092,"date":"2016-12-20T22:07:03","date_gmt":"2016-12-20T22:07:03","guid":{"rendered":"https:\/\/www.modernescpp.com\/index.php\/copy-versus-move-semantic-a-few-numbers\/"},"modified":"2023-06-26T12:31:17","modified_gmt":"2023-06-26T12:31:17","slug":"copy-versus-move-semantic-a-few-numbers","status":"publish","type":"post","link":"https:\/\/www.modernescpp.com\/index.php\/copy-versus-move-semantic-a-few-numbers\/","title":{"rendered":"Copy versus Move Semantics: A few Numbers"},"content":{"rendered":"<p>A lot was written about the advantages of move semantics to copy semantics. Instead of an expensive copy operation, you can use a cheap move operation. But what does that mean? In this post, I will compare the copy and move semantics performance for the Standard Template Library (STL) containers.&nbsp;<\/p>\n<p><!--more--><\/p>\n<p>&nbsp;<\/p>\n<p>Before I show the number, I will provide some background information.<\/p>\n<h2>Copy versus Move Semantics<\/h2>\n<p>The subtle difference is if you create with a copy or move semantic a new object based on an existing one, the copy semantic will copy the elements of the resource, and the move semantic will move the elements of the resource. Of course, copying is expensive, and moving is cheap. But there are additional serious consequences.<\/p>\n<ol>\n<li>With copy semantic, it can happen that a <span style=\"font-family: courier new,courier;\"><a href=\"http:\/\/en.cppreference.com\/w\/cpp\/memory\/new\/bad_alloc\">std::bad_alloc<\/a><\/span> will be thrown because your program is out of memory.<\/li>\n<li>The resource of the move operation is afterward in a &#8220;<em>valid but unspecified state<\/em>&#8220;.<\/li>\n<\/ol>\n<p>The second point is very nice to show with&nbsp;<span style=\"font-family: courier new,courier;\">std::string<\/span>.<\/p>\n<p>At first, the classical copy semantics.<\/p>\n<h3>Copy semantics<\/h3>\n<div style=\"background: #ffffff; overflow: auto; width: auto; gray;border-width: .1em .1em .1em .8em;\">\n<pre style=\"margin: 0; line-height: 125%;\">std::string1(<span style=\"color: #a31515;\">\"ABCDEF\"<\/span>);\r\nstd::string str2;\r\nstr2 = str1;\r\n<\/pre>\n<\/div>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-5087\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2016\/12\/copy.jpg\" alt=\"copy\" width=\"658\" height=\"252\" style=\"margin: 15px;\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2016\/12\/copy.jpg 658w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2016\/12\/copy-300x115.jpg 300w\" sizes=\"auto, (max-width: 658px) 100vw, 658px\" \/><\/p>\n<p>After the copy operation, strings str1 and str2 have the same content, &#8220;<span style=\"font-family: courier new,courier;\">ABCDEF<\/span>&#8220;. So, what&#8217;s the difference between the move semantics?<\/p>\n<h3>Move semantics<\/h3>\n<p>&nbsp;<\/p>\n<div style=\"background: #ffffff; overflow: auto; width: auto; gray;border-width: .1em .1em .1em .8em;\">\n<pre style=\"margin: 0; line-height: 125%;\">std::string1(<span style=\"color: #a31515;\">\"ABCDEF\"<\/span>);\r\nstd::string str3;\r\nstr3 = std::move(str1);\r\n<\/pre>\n<\/div>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-5088\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2016\/12\/move.jpg\" alt=\"move\" width=\"659\" height=\"225\" style=\"margin: 15px;\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2016\/12\/move.jpg 659w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2016\/12\/move-300x102.jpg 300w\" sizes=\"auto, (max-width: 659px) 100vw, 659px\" \/><\/p>\n<p>The string <span style=\"font-family: courier new,courier;\">str1<\/span> opposes the copy semantic afterward empty &#8220;&#8221;. This is not guaranteed but often the case. I explicitly requested the move semantic with the function <span style=\"font-family: courier new,courier;\"><a href=\"http:\/\/de.cppreference.com\/w\/cpp\/utility\/move\">std::move<\/a><\/span>. The compiler will automatically perform the move semantic if it is sure that the source of the move semantic is not needed anymore.<\/p>\n<p>I will explicitly request the move semantic in my program by using <span style=\"font-family: courier new,courier;\">std::move.<\/span><\/p>\n<\/p>\n<h2>The Performance Differences<\/h2>\n<p>I will take the naive position in my post and compare the performance difference between the copy and move semantics of the STL containers. My comparison will include the <span style=\"font-family: courier new,courier;\">std::string<\/span>. I will ignore the <a href=\"https:\/\/www.modernescpp.com\/index.php\/hash-tables\">associative containers<\/a>, which can have more equal keys. I&#8217;m particularly interested in the performance ratio between the copy and move semantics of the containers.<\/p>\n<h3>The boundary conditions<\/h3>\n<p>The differences were not so dramatic between the program with maximum optimization and without optimization; therefore, I will, for simplicity reasons, only provide the results for the executable with maximum optimization. I use a GCC 4.9.2 compiler and the cl.exe compiler, which is part of Microsoft Visual Studio 2015. Both platforms are 64-bit. Therefore, the executables are built for 64-bit.&nbsp;<\/p>\n<h3>The program<\/h3>\n<p>We have a lot of containers in the STL. Therefore, the program is a little bit lengthy.<\/p>\n<div style=\"background: #ffffff; overflow: auto; width: auto; gray;border-width: .1em .1em .1em .8em;\">\n<table>\n<tbody>\n<tr>\n<td>\n<pre style=\"margin: 0; line-height: 125%;\">  1\r\n  2\r\n  3\r\n  4\r\n  5\r\n  6\r\n  7\r\n  8\r\n  9\r\n 10\r\n 11\r\n 12\r\n 13\r\n 14\r\n 15\r\n 16\r\n 17\r\n 18\r\n 19\r\n 20\r\n 21\r\n 22\r\n 23\r\n 24\r\n 25\r\n 26\r\n 27\r\n 28\r\n 29\r\n 30\r\n 31\r\n 32\r\n 33\r\n 34\r\n 35\r\n 36\r\n 37\r\n 38\r\n 39\r\n 40\r\n 41\r\n 42\r\n 43\r\n 44\r\n 45\r\n 46\r\n 47\r\n 48\r\n 49\r\n 50\r\n 51\r\n 52\r\n 53\r\n 54\r\n 55\r\n 56\r\n 57\r\n 58\r\n 59\r\n 60\r\n 61\r\n 62\r\n 63\r\n 64\r\n 65\r\n 66\r\n 67\r\n 68\r\n 69\r\n 70\r\n 71\r\n 72\r\n 73\r\n 74\r\n 75\r\n 76\r\n 77\r\n 78\r\n 79\r\n 80\r\n 81\r\n 82\r\n 83\r\n 84\r\n 85\r\n 86\r\n 87\r\n 88\r\n 89\r\n 90\r\n 91\r\n 92\r\n 93\r\n 94\r\n 95\r\n 96\r\n 97\r\n 98\r\n 99\r\n100\r\n101\r\n102\r\n103\r\n104\r\n105<\/pre>\n<\/td>\n<td>\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #008000;\">\/\/ movePerformance.cpp<\/span>\r\n \r\n<span style=\"color: #0000ff;\">#include &lt;array&gt;<\/span>\r\n<span style=\"color: #0000ff;\">#include &lt;forward_list&gt;<\/span>\r\n<span style=\"color: #0000ff;\">#include &lt;chrono&gt;<\/span>\r\n<span style=\"color: #0000ff;\">#include &lt;deque&gt;<\/span>\r\n<span style=\"color: #0000ff;\">#include &lt;iomanip&gt;<\/span>\r\n<span style=\"color: #0000ff;\">#include &lt;iostream&gt;<\/span>\r\n<span style=\"color: #0000ff;\">#include &lt;list&gt;<\/span>\r\n<span style=\"color: #0000ff;\">#include &lt;map&gt;<\/span>\r\n<span style=\"color: #0000ff;\">#include &lt;numeric&gt;<\/span>\r\n<span style=\"color: #0000ff;\">#include &lt;set&gt;<\/span>\r\n<span style=\"color: #0000ff;\">#include &lt;string&gt;<\/span>\r\n<span style=\"color: #0000ff;\">#include &lt;unordered_map&gt;<\/span>\r\n<span style=\"color: #0000ff;\">#include &lt;unordered_set&gt;<\/span>\r\n<span style=\"color: #0000ff;\">#include &lt;utility&gt;<\/span>\r\n<span style=\"color: #0000ff;\">#include &lt;vector&gt;<\/span>\r\n\r\n<span style=\"color: #0000ff;\">const<\/span> <span style=\"color: #2b91af;\">int<\/span> SIZE = 10000000; \r\n\r\n<span style=\"color: #0000ff;\">template<\/span> &lt;<span style=\"color: #0000ff;\">typename<\/span> T&gt;\r\n<span style=\"color: #2b91af;\">void<\/span> measurePerformance(T&amp; t, <span style=\"color: #0000ff;\">const<\/span> std::string&amp; cont){\r\n  \r\n  std::cout &lt;&lt; std::fixed &lt;&lt; std::setprecision(10);\r\n\r\n  <span style=\"color: #0000ff;\">auto<\/span> begin= std::chrono::system_clock::now();\r\n  T t1(t);\r\n  <span style=\"color: #0000ff;\">auto<\/span> last=  std::chrono::system_clock::now() - begin;\r\n  std::cout &lt;&lt; cont &lt;&lt; std::endl;\r\n  <span style=\"color: #0000ff;\">auto<\/span> copyTime=  std::chrono::duration&lt;<span style=\"color: #2b91af;\">double<\/span>&gt;(last).count();\r\n  std::cout &lt;&lt;  <span style=\"color: #a31515;\">\"    Copy: \"<\/span> &lt;&lt; copyTime &lt;&lt; <span style=\"color: #a31515;\">\" sec\"<\/span> &lt;&lt; std::endl;\r\n\r\n  begin= std::chrono::system_clock::now();\r\n  T t2(std::move(t));\r\n  last=  std::chrono::system_clock::now() - begin;\r\n  <span style=\"color: #0000ff;\">auto<\/span> moveTime= std::chrono::duration&lt;<span style=\"color: #2b91af;\">double<\/span>&gt;(last).count();\r\n  std::cout &lt;&lt;  <span style=\"color: #a31515;\">\"    Move: \"<\/span> &lt;&lt; moveTime &lt;&lt; <span style=\"color: #a31515;\">\" sec\"<\/span> &lt;&lt; std::endl;\r\n  \r\n  std::cout &lt;&lt; std::setprecision(2);\r\n  std::cout &lt;&lt; <span style=\"color: #a31515;\">\"    Ratio (copy time\/move time): \"<\/span> &lt;&lt; (copyTime\/moveTime) &lt;&lt; std::endl;\r\n  \r\n  std::cout &lt;&lt; std::endl;\r\n     \r\n}\r\n\r\n<span style=\"color: #2b91af;\">int<\/span> main(){\r\n    \r\n    std::cout &lt;&lt; std::endl;\r\n    \r\n    {\r\n      std::array&lt;<span style=\"color: #2b91af;\">int<\/span>,SIZE\/1000&gt; myArray;\r\n      measurePerformance(myArray,<span style=\"color: #a31515;\">\"std::array&lt;int,SIZE\/1000&gt;\"<\/span>);   \r\n    }\r\n    \r\n    {\r\n      std::vector&lt;<span style=\"color: #2b91af;\">int<\/span>&gt; myVec(SIZE);\r\n      measurePerformance(myVec,<span style=\"color: #a31515;\">\"std::vector&lt;int&gt;(SIZE)\"<\/span>);\r\n    }\r\n\r\n    {\r\n      std::deque&lt;<span style=\"color: #2b91af;\">int<\/span>&gt;myDec(SIZE);\r\n      measurePerformance(myDec,<span style=\"color: #a31515;\">\"std::deque&lt;int&gt;(SIZE)\"<\/span>);\r\n    }\r\n    \r\n    {\r\n      std::list&lt;<span style=\"color: #2b91af;\">int<\/span>&gt;myList(SIZE);\r\n      measurePerformance(myList,<span style=\"color: #a31515;\">\"std::list&lt;int&gt;(SIZE)\"<\/span>);\r\n    }\r\n    \r\n    {\r\n      std::forward_list&lt;<span style=\"color: #2b91af;\">int<\/span>&gt;myForwardList(SIZE);\r\n      measurePerformance(myForwardList,<span style=\"color: #a31515;\">\"std::forward_list&lt;int&gt;(SIZE)\"<\/span>);\r\n    } \r\n       \r\n    {\r\n      std::string myString(SIZE,<span style=\"color: #a31515;\">' '<\/span>);\r\n      measurePerformance(myString,<span style=\"color: #a31515;\">\"std::string(SIZE,' ')\"<\/span>);\r\n    }\r\n    \r\n    std::vector&lt;<span style=\"color: #2b91af;\">int<\/span>&gt; tmpVec(SIZE);\r\n    std::iota(tmpVec.begin(),tmpVec.end(),0);\r\n    \r\n    {\r\n      std::set&lt;<span style=\"color: #2b91af;\">int<\/span>&gt;mySet(tmpVec.begin(),tmpVec.end());\r\n      measurePerformance(mySet,<span style=\"color: #a31515;\">\"std::set&lt;int&gt;\"<\/span>);\r\n    }\r\n    \r\n    {\r\n      std::unordered_set&lt;<span style=\"color: #2b91af;\">int<\/span>&gt;myUnorderedSet(tmpVec.begin(),tmpVec.end());\r\n      measurePerformance(myUnorderedSet,<span style=\"color: #a31515;\">\"std::unordered_set&lt;int&gt;\"<\/span>);\r\n    }\r\n    \r\n    {\r\n      std::map&lt;<span style=\"color: #2b91af;\">int<\/span>,<span style=\"color: #2b91af;\">int<\/span>&gt;myMap;\r\n      <span style=\"color: #0000ff;\">for<\/span> (<span style=\"color: #0000ff;\">auto<\/span> i= 0; i &lt;= SIZE; ++i) myMap[i]= i;\r\n      measurePerformance(myMap,<span style=\"color: #a31515;\">\"std::map&lt;int,int&gt;\"<\/span>);\r\n    }\r\n    \r\n    {\r\n      std::unordered_map&lt;<span style=\"color: #2b91af;\">int<\/span>,<span style=\"color: #2b91af;\">int<\/span>&gt;myUnorderedMap;\r\n      <span style=\"color: #0000ff;\">for<\/span> (<span style=\"color: #0000ff;\">auto<\/span> i= 0; i &lt;= SIZE; ++i) myUnorderedMap[i]= i;\r\n      measurePerformance(myUnorderedMap,<span style=\"color: #a31515;\">\"std::unordered_map&lt;int,int&gt;\"<\/span>);\r\n    }  \r\n    \r\n}\r\n<\/pre>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<p>&nbsp;<\/p>\n<p>The idea of the program is to initialize&nbsp;the containers with 10 million elements. Of course, the initialization will happen with copy and move semantics. The performance measurement occurs in the function template measurePerformane (lines 21 &#8211; 44). The function takes as an argument the container and the name of the container. Thanks to the Chrono library I can measure how long the copy initialization (line 27) and the move initialization (line 34) take. Ultimately, I&#8217;m interested in the ratio between the copy and move semantics (line 40).<\/p>\n<p>What&#8217;s happening in the main function? I create each container with its scope so that it will be automatically released. Therefore, myArray (line 51) will automatically be released and the end of its scope (line 53). Because the containers are quite big, releasing their memory is a must. I claimed that each container has 10 million elements. That will not hold for myArray. Because myArray will not be allocated on the heap, I must dramatically reduce its size. But now to the remaining containers. With <span style=\"font-family: courier new,courier;\">std::vector,<\/span> <span style=\"font-family: courier new,courier;\">std::deque,<\/span> <span style=\"font-family: courier new,courier;\">std::list<\/span>, and <span style=\"font-family: courier new,courier;\">std::forward_list<\/span> there are in lines 55 &#8211; 73 the remaining sequential containers. In lines 75 &#8211; 78 <span style=\"font-family: courier new,courier;\">std::string<\/span> follows. The rest are the associative containers. I have to pay attention to one characteristic of the associative container. To have unique keys and therefore the size 10 million, I use the numbers 0 to 9999999 as keys. The function <span style=\"font-family: courier new,courier;\">std::iota<\/span>&nbsp;does the job.<span style=\"font-family: courier new,courier;\"><\/span><\/p>\n<h3>The numbers<\/h3>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-5089\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2016\/12\/move.png\" alt=\"move\" width=\"493\" height=\"896\" style=\"margin: 15px;\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2016\/12\/move.png 493w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2016\/12\/move-165x300.png 165w\" sizes=\"auto, (max-width: 493px) 100vw, 493px\" \/><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-5090\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2016\/12\/moveWin.PNG\" alt=\"moveWin\" width=\"556\" height=\"1046\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2016\/12\/moveWin.PNG 556w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2016\/12\/moveWin-159x300.png 159w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2016\/12\/moveWin-544x1024.png 544w\" sizes=\"auto, (max-width: 556px) 100vw, 556px\" \/><\/p>\n<p>&nbsp;<\/p>\n<p>The results of <span style=\"font-family: courier new,courier;\">std::array<\/span> are not so meaningful. On the one hand, <span style=\"font-family: courier new,courier;\">std::array<\/span> is not so big; on the other hand, the time difference on Windows is not measurable with the clock <span style=\"font-family: courier new,courier;\">std::system_clock<\/span>.&nbsp;<\/p>\n<p>What insight can I derive from the numbers?<\/p>\n<ul>\n<li><strong>Sequential container<\/strong>: <span style=\"font-family: courier new,courier;\">std::vector<\/span> is the fastest container in case of copying or moving.<\/li>\n<li><strong>Sequential versus associative container<\/strong>: Copying the sequential container on Linux and Windows is faster.<\/li>\n<li><strong>Copy versus move semantics<\/strong>: The differences between the copy and move semantics are huge. That holds, in particular, true for the associative containers.&nbsp;<\/li>\n<li><span style=\"font-family: courier new,courier;\"><strong>std::string<\/strong>:<\/span> The <span style=\"font-family: courier new,courier;\">std::string<\/span> on Linux behaves strangely. On the one hand, copying is very fast; on the other hand, moving is only 16 times faster than copying. The becomes even more strange if I compile and execute the program without optimization. I get the result on Linux that the move semantics is only 1.5 times faster than the copy semantics. But these numbers are in strong contradiction to the numbers on Windows. On Windows, the move semantic is 15000 times faster than the copy semantic.&nbsp;<\/li>\n<\/ul>\n<h3>The riddle around std::string<\/h3>\n<p>The performance difference between the copy and move semantics on Linux and Windows is quickly explained. My GCC implements the<span style=\"font-family: courier new,courier;\"> std::string<\/span> according to <a href=\"https:\/\/en.wikipedia.org\/wiki\/Copy-on-write\">copy-on-write<\/a> (cow). This is not conformant to the C++11 standard. But cl.exe implements <span style=\"font-family: courier new,courier;\">std::string<\/span> according to the C++11 standard. I will get different numbers if I compile the program with GCC 6.1 and enable C++11. GCC&#8217;s <span style=\"font-family: courier new,courier;\">std::string<\/span> implementation is since 5.1 conformant to the C++11 standard.<\/p>\n<p>Here are the numbers with the online compiler on <a href=\"http:\/\/en.cppreference.com\/w\/\">en.cppreference.com.<\/a><span style=\"font-family: courier new,courier;\"><\/span><\/p>\n<p>&nbsp;<img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-5091\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2016\/12\/string.png\" alt=\"string\" style=\"margin: 15px;\" width=\"413\" height=\"99\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2016\/12\/string.png 413w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2016\/12\/string-300x72.png 300w\" sizes=\"auto, (max-width: 413px) 100vw, 413px\" \/><\/p>\n<p>Now, there is a big difference between the copy and move semantics.&nbsp;<\/p>\n<h2>What&#8217;s next?<\/h2>\n<p>I hope that was the motivation for the move semantics. In the <a href=\"https:\/\/www.modernescpp.com\/index.php\/move-semantic-tow-nice-properties\">next post<\/a>, I will pick two nice characteristics of the move semantic.<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>A lot was written about the advantages of move semantics to copy semantics. Instead of an expensive copy operation, you can use a cheap move operation. But what does that mean? In this post, I will compare the copy and move semantics performance for the Standard Template Library (STL) containers.&nbsp;<\/p>\n","protected":false},"author":21,"featured_media":5087,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[364],"tags":[498,494],"class_list":["post-5092","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-embedded","tag-memory","tag-move"],"_links":{"self":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/5092","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/users\/21"}],"replies":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/comments?post=5092"}],"version-history":[{"count":1,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/5092\/revisions"}],"predecessor-version":[{"id":6910,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/5092\/revisions\/6910"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media\/5087"}],"wp:attachment":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media?parent=5092"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/categories?post=5092"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/tags?post=5092"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}