title: (Missing) performance improvements with C++11 move semantics
body: <p>I've been writing C++11 code for quite some time now, and haven't done any benchmarking of it, only expecting things like vector operations to "just be faster" now with move semantics. So when actually benchmarking with GCC 4.7.2 and clang 3.0 (default compilers on Ubuntu 12.10 64-bit) I get very unsatisfying results. This is my test code:</p>
  
  <p><strong>EDIT:</strong> With regards to the (good) answers posted by @DeadMG and @ronag, I changed the element type from <code>std::string</code> to <code>my::string</code> which does not have a <code>swap()</code>, and made all inner strings larger (200-700 bytes) so that they shouldn't be the <em>victims</em> of SSO.</p>
  
  <p><strong>EDIT2:</strong> COW was the reason. Adapted code again by the great comments, changed the storage from <code>std::string</code> to <code>std::vector&lt;char&gt;</code> and leaving out copy/move onstructors (letting the compiler generate them instead). Without COW, the speed difference is actually huge.</p>
  
  <p><strong>EDIT3:</strong> Re-added the previous solution when compiled with <code>-DCOW</code>. This makes the internal storage a <code>std::string</code> rather than a <code>std::vector&lt;char&gt;</code> as requested by @chico.</p>
  
  <pre><code>#include &lt;string&gt;
  #include &lt;vector&gt;
  #include &lt;fstream&gt;
  #include &lt;iostream&gt;
  #include &lt;algorithm&gt;
  #include &lt;functional&gt;
  
  static std::size_t dec = 0;
  
  namespace my { class string
  {
  public:
      string( ) { }
  #ifdef COW
      string( const std::string&amp; ref ) : str( ref ), val( dec % 2 ? - ++dec : ++dec ) {
  #else
      string( const std::string&amp; ref ) : val( dec % 2 ? - ++dec : ++dec ) {
          str.resize( ref.size( ) );
          std::copy( ref.begin( ), ref.end( ), str.begin( ) );
  #endif
      }
  
      bool operator&lt;( const string&amp; other ) const { return val &lt; other.val; }
  
  private:
  #ifdef COW
      std::string str;
  #else
      std::vector&lt; char &gt; str;
  #endif
      std::size_t val;
  }; }
  
  
  template&lt; typename T &gt;
  void dup_vector( T&amp; vec )
  {
      T v = vec;
      for ( typename T::iterator i = v.begin( ); i != v.end( ); ++i )
  #ifdef CPP11
          vec.push_back( std::move( *i ) );
  #else
          vec.push_back( *i );
  #endif
  }
  
  int main( )
  {
      std::ifstream file;
      file.open( "/etc/passwd" );
      std::vector&lt; my::string &gt; lines;
      while ( ! file.eof( ) )
      {
          std::string s;
          std::getline( file, s );
          lines.push_back( s + s + s + s + s + s + s + s + s );
      }
  
      while ( lines.size( ) &lt; ( 1000 * 1000 ) )
          dup_vector( lines );
      std::cout &lt;&lt; lines.size( ) &lt;&lt; " elements" &lt;&lt; std::endl;
  
      std::sort( lines.begin( ), lines.end( ) );
  
      return 0;
  }
  </code></pre>
  
  <p>What this does is read /etc/passwd into a vector of lines, then duplicating this vector onto itself over and over until we have at least 1 million entries. This is where the first optimization should be useful, not only the explicit <code>std::move()</code> you see in <code>dup_vector()</code>, but also the <code>push_back</code> per se should perform better when it needs to resize (create new + copy) the inner array.</p>
  
  <p>Finally, the vector is sorted. This should definitely be faster when you don't need to copy temporary objects each time two elements are swapped.</p>
  
  <p>I compile and run this two ways, one being as C++98, the next as C++11 (with -DCPP11 for the explicit move):</p>
  
  <pre><code>1&gt; $ rm -f a.out ; g++ --std=c++98 test.cpp ; time ./a.out
  2&gt; $ rm -f a.out ; g++ --std=c++11 -DCPP11 test.cpp ; time ./a.out
  3&gt; $ rm -f a.out ; clang++ --std=c++98 test.cpp ; time ./a.out
  4&gt; $ rm -f a.out ; clang++ --std=c++11 -DCPP11 test.cpp ; time ./a.out
  </code></pre>
  
  <p>With the following results (twice for each compilation):</p>
  
  <pre><code>GCC C++98
  1&gt; real 0m9.626s
  1&gt; real 0m9.709s
  
  GCC C++11
  2&gt; real 0m10.163s
  2&gt; real 0m10.130s
  </code></pre>
  
  <p>So, it's slightly slower to run when compiled as C++11 code. Similar results goes for clang:</p>
  
  <pre><code>clang C++98
  3&gt; real 0m8.906s
  3&gt; real 0m8.750s
  
  clang C++11
  4&gt; real 0m8.858s
  4&gt; real 0m9.053s
  </code></pre>
  
  <p>Can someone tell me why this is? Are the compilers optimizing so good even when compiling for pre-C++11, that they practically reach move semantic behaviour after all? If I add <code>-O2</code>, all code runs faster, but the results between the different standards are almost the same as above.</p>
  
  <p><strong>EDIT</strong>: New results with my::string and rather than std::string, and larger individual strings:</p>
  
  <pre><code>$ rm -f a.out ; g++ --std=c++98 test.cpp ; time ./a.out
  real    0m16.637s
  $ rm -f a.out ; g++ --std=c++11 -DCPP11 test.cpp ; time ./a.out
  real    0m17.169s
  $ rm -f a.out ; clang++ --std=c++98 test.cpp ; time ./a.out
  real    0m16.222s
  $ rm -f a.out ; clang++ --std=c++11 -DCPP11 test.cpp ; time ./a.out
  real    0m15.652s
  </code></pre>
  
  <p>There are <strong>very</strong> small differences between C++98 and C+11 with move semantics. Slightly slower with C++11 with GCC and slightly faster with clang, but still very small differencies.</p>
  
  <p><strong>EDIT2:</strong> Now without <code>std::string</code>'s COW, the performance improvement is huge:</p>
  
  <pre><code>$ rm -f a.out ; g++ --std=c++98 test.cpp ; time ./a.out
  real    0m10.313s
  $ rm -f a.out ; g++ --std=c++11 -DCPP11 test.cpp ; time ./a.out
  real    0m5.267s
  $ rm -f a.out ; clang++ --std=c++98 test.cpp ; time ./a.out
  real    0m10.218s
  $ rm -f a.out ; clang++ --std=c++11 -DCPP11 test.cpp ; time ./a.out
  real    0m3.376s
  </code></pre>
  
  <p>With optimization, the difference is a lot bigger too:</p>
  
  <pre><code>$ rm -f a.out ; g++ -O2 --std=c++98 test.cpp ; time ./a.out
  real    0m5.243s
  $ rm -f a.out ; g++ -O2 --std=c++11 -DCPP11 test.cpp ; time ./a.out
  real    0m0.803s
  $ rm -f a.out ; clang++ -O2 --std=c++98 test.cpp ; time ./a.out
  real    0m5.248s
  $ rm -f a.out ; clang++ -O2 --std=c++11 -DCPP11 test.cpp ; time ./a.out
  real    0m0.785s
  </code></pre>
  
  <p>Above showing a factor of ~6-7 times faster with C++11.</p>
  
  <p>Thanks for the great comments and answers. I hope this post will be useful and interesting to others too.</p>