title: std::vector<uint8_t> manually copying instead of calling memcpy when C++11/14 enabled
body: <p>Using gcc 4.9, cross-compiling for ARM using the Linaro toolchain, I have found the compiled result of <code>vector.assign()</code> changes when adding <code>-std=c++14</code>, in a way that creates significant performance problems.</p>
  
  <p>I have tried several different ways of doing this allocation + copy, but all of them have this performance problem as long as I'm using <code>std::vector</code> to do it. </p>
  
  <p>I can reproduce the problem with this toy example:</p>
  
  <p><strong>VectorTest.h</strong></p>
  
  <pre><code>#include &lt;stdint.h&gt;
  #include &lt;stddef.h&gt;
  #include &lt;vector&gt;
  
  struct VectorWrapper_t
  {
      VectorWrapper_t(uint8_t const* pData, size_t length);
      std::vector&lt;uint8_t&gt; data;
  };
  </code></pre>
  
  <p><strong>VectorTest.cpp</strong></p>
  
  <pre><code>#include "VectorTest.h"
  
  VectorWrapper_t::VectorWrapper_t(uint8_t const* pData, size_t length)
  {
      data.assign(pData, pData + length);
  }
  </code></pre>
  
  <p>gcc flags:</p>
  
  <pre><code>-std=c++14 \
  -mthumb -march=armv7-a -mtune=cortex-a9 \
  -mlittle-endian -mfloat-abi=hard -mfpu=neon -Wa,-mimplicit-it=thumb \
  -O2 -g
  </code></pre>
  
  <p>Viewing the assembly, I can see why: the original version (C++03, I'm assuming?) calls <code>memmove</code>, whereas the C++14 version instead adds an extra loop that it looks like is copying the data manually. Looking at the <code>.loc</code> tags gcc adds with <code>-fverbose-asm</code>, the instructions in this loop come from <code>stl_construct.h</code> and <code>stl_uninitialized.h</code>.</p>
  
  <p>Changing to gcc 5.2.1 (with C++14), it compiles nearly identically to the C++03 example, except with <code>memcpy</code> instead of <code>memmove</code>.</p>
  
  <p>I'm able to get around this problem by using <code>std::unique_ptr&lt;uint8_t[]&gt;</code> instead of a <code>vector</code> here. However, I would like to get to the bottom of this issue to figure out if other places using <code>vector</code>s could have performance problems and how to potentially fix them (updating to gcc 5.2 isn't practical).</p>
  
  <p>So my question is: <strong>Why does it compile differently under C++11/14?</strong></p>
  
  <p>For reference, <code>gcc --version</code> reports:<br>
  <code>arm-linux-gnueabihf-gcc (Linaro GCC 4.9-2014.12) 4.9.3 20141205 (prerelease)</code>.</p>
  
  <p>Here is the assembly gcc generated:</p>
  
  <pre><code># C++03, gcc 4.9
  
      push    {r3, r4, r5, r6, r7, lr}    @
      movs    r3, #0  @ tmp118,
      mov r4, r0  @ this, this
      str r3, [r0]    @ tmp118, MEM[(struct _Vector_impl *)this_1(D)]._M_start
      mov r5, r2  @ length, length
      str r3, [r0, #4]    @ tmp118, MEM[(struct _Vector_impl *)this_1(D)]._M_finish
      str r3, [r0, #8]    @ tmp118, MEM[(struct _Vector_impl *)this_1(D)]._M_end_of_storage
      cbnz    r2, .L19    @ length,
      mov r0, r4  @, this
      pop {r3, r4, r5, r6, r7, pc}    @
  .L19:
      mov r0, r2  @, length
      mov r6, r1  @ pData, pData
      bl  _Znwj   @
      mov r2, r5  @, length
      mov r1, r6  @, pData
      mov r7, r0  @ D.13516,
      bl  memmove @
      ldr r0, [r4]    @ D.13515, MEM[(struct vector *)this_1(D)].D.11902._M_impl._M_start
      cbz r0, .L3 @ D.13515,
      bl  _ZdlPv  @
  .L3:
      add r5, r5, r7  @ D.13515, D.13516
      str r7, [r4]    @ D.13516, MEM[(struct vector *)this_1(D)].D.11902._M_impl._M_start
      str r5, [r4, #4]    @ D.13515, MEM[(struct vector *)this_1(D)].D.11902._M_impl._M_finish
      mov r0, r4  @, this
      str r5, [r4, #8]    @ D.13515, MEM[(struct vector *)this_1(D)].D.11902._M_impl._M_end_of_storage
      pop {r3, r4, r5, r6, r7, pc}    @
  .L6:
      ldr r0, [r4]    @ D.13515, MEM[(struct _Vector_base *)this_1(D)]._M_impl._M_start
      cbz r0, .L5 @ D.13515,
      bl  _ZdlPv  @
  .L5:
      bl  __cxa_end_cleanup   @
  
  # C++14, gcc 4.9
  
      push    {r3, r4, r5, r6, r7, lr}    @
      movs    r3, #0  @ tmp157,
      mov r6, r0  @ this, this
      str r3, [r0]    @ tmp157, MEM[(struct _Vector_impl *)this_1(D)]._M_start
      mov r5, r2  @ length, length
      str r3, [r0, #4]    @ tmp157, MEM[(struct _Vector_impl *)this_1(D)]._M_finish
      str r3, [r0, #8]    @ tmp157, MEM[(struct _Vector_impl *)this_1(D)]._M_end_of_storage
      cbnz    r2, .L25    @ length,
      mov r0, r6  @, this
      pop {r3, r4, r5, r6, r7, pc}    @
  .L25:
      mov r0, r2  @, length
      mov r4, r1  @ pData, pData
      bl  _Znwj   @
      adds    r3, r4, r5  @ D.20345, pData, length
      mov r7, r0  @ __result,
      cmp r4, r3  @ pData, D.20345
      ittt    ne
      addne   r1, r4, #-1 @ ivtmp.76, pData,
      movne   r3, r0  @ __result, __result
      addne   r4, r0, r5  @ D.20346, __result, length
      beq .L26    @,
  .L7:
      ldrb    r2, [r1, #1]!   @ zero_extendqisi2  @ D.20348, MEM[base: _48, offset: 0]
      cbz r3, .L6 @ __result,
      strb    r2, [r3]    @ D.20348, MEM[base: __result_23, offset: 0B]
  .L6:
      adds    r3, r3, #1  @ __result, __result,
      cmp r3, r4  @ __result, D.20346
      bne .L7 @,
  .L8:
      ldr r0, [r6]    @ D.20346, MEM[(struct vector *)this_1(D)].D.18218._M_impl._M_start
      cbz r0, .L5 @ D.20346,
      bl  _ZdlPv  @
  .L5:
      str r7, [r6]    @ __result, MEM[(struct vector *)this_1(D)].D.18218._M_impl._M_start
      mov r0, r6  @, this
      str r4, [r6, #4]    @ D.20346, MEM[(struct vector *)this_1(D)].D.18218._M_impl._M_finish
      str r4, [r6, #8]    @ D.20346, MEM[(struct vector *)this_1(D)].D.18218._M_impl._M_end_of_storage
      pop {r3, r4, r5, r6, r7, pc}    @
  .L26:
      adds    r4, r0, r5  @ D.20346, __result, length
      b   .L8 @
  .L11:
      ldr r0, [r6]    @ D.20346, MEM[(struct _Vector_base *)this_1(D)]._M_impl._M_start
      cbz r0, .L10    @ D.20346,
      bl  _ZdlPv  @
  .L10:
      bl  __cxa_end_cleanup   @
  
  # C++14, gcc 5.2
  
      push    {r3, r4, r5, r6, r7, lr}    @
      movs    r3, #0  @ tmp118,
      mov r4, r0  @ this, this
      str r3, [r0]    @ tmp118, MEM[(struct _Vector_impl *)this_1(D)]._M_start
      str r3, [r0, #4]    @ tmp118, MEM[(struct _Vector_impl *)this_1(D)]._M_finish
      str r3, [r0, #8]    @ tmp118, MEM[(struct _Vector_impl *)this_1(D)]._M_end_of_storage
      cbnz    r2, .L19    @ length,
      mov r0, r4  @, this
      pop {r3, r4, r5, r6, r7, pc}    @
  .L19:
      mov r0, r2  @, length
      mov r6, r1  @ pData, pData
      mov r5, r2  @ length, length
      bl  _Znwj   @
      mov r2, r5  @, length
      mov r1, r6  @, pData
      mov r7, r0  @ D.20824,
      bl  memcpy  @
      ldr r0, [r4]    @ D.20823, MEM[(struct vector *)this_1(D)].D.18751._M_impl._M_start
      cbz r0, .L3 @ D.20823,
      bl  _ZdlPv  @
  .L3:
      add r5, r5, r7  @ D.20823, D.20824
      str r7, [r4]    @ D.20824, MEM[(struct vector *)this_1(D)].D.18751._M_impl._M_start
      str r5, [r4, #4]    @ D.20823, MEM[(struct vector *)this_1(D)].D.18751._M_impl._M_finish
      mov r0, r4  @, this
      str r5, [r4, #8]    @ D.20823, MEM[(struct vector *)this_1(D)].D.18751._M_impl._M_end_of_storage
      pop {r3, r4, r5, r6, r7, pc}    @
  .L6:
      ldr r0, [r4]    @ D.20823, MEM[(struct _Vector_base *)this_1(D)]._M_impl._M_start
      cbz r0, .L5 @ D.20823,
      bl  _ZdlPv  @
  .L5:
      bl  __cxa_end_cleanup   @
  </code></pre>