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
retqAfter:
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