This change optimizes the move assignment operator to more efficient / compact code, and fixes a bug.
Move assignment optimization:
- do not use the (expensive / branched) clear_and_shrink() method but inline size = 0
- only zero existing instance in the presence of potential exceptions
Result (std::string): more compact code, single branch
Bug fix:
- an exception thrown by the alloc move assignment would leave the current instance in a bad state with a non null pointer owned by the moved from instance, not owned by the current alloc. Swap the alloc move and assignment of __r_r.first()
Given:
void MoveAssign(std::string* d, std::string* s) { *d = std::move(*s); }
Before:
pushq %r14 pushq %rbx pushq %rax movq %rsi, %r14 movq %rdi, %rbx cmpb $0, 23(%rdi) js .LBB2_2 movb $0, (%rbx) movb $0, 23(%rbx) jmp .LBB2_4 .LBB2_2: movq (%rbx), %rax movb $0, (%rax) movq $0, 8(%rbx) cmpb $0, 23(%rbx) jns .LBB2_4 movq (%rbx), %rdi callq operator delete(void*) movq $0, 16(%rbx) .LBB2_4: movq 16(%r14), %rax movq %rax, 16(%rbx) movups (%r14), %xmm0 movups %xmm0, (%rbx) xorps %xmm0, %xmm0 movups %xmm0, (%r14) movq $0, 16(%r14) addq $8, %rsp popq %rbx popq %r14 retq
After:
push r14 push rbx push rax mov rbx, rsi mov r14, rdi cmp byte ptr [rdi + 23], 0 jns .LBB2_2 mov rdi, qword ptr [r14] call operator delete(void*) .LBB2_2: mov rax, qword ptr [rbx + 16] mov qword ptr [r14 + 16], rax movups xmm0, xmmword ptr [rbx] movups xmmword ptr [r14], xmm0 mov byte ptr [rbx], 0 mov byte ptr [rbx + 23], 0 add rsp, 8 pop rbx pop r14 ret