As pointed in the linked answer for an optimized case of a class with a single owning-pointer:
Move constructor
MyClass(MyClass&& rhs):
ptr(rhs.ptr) { // load rhs.ptr, store it in ptr
rhs.ptr = nullptr; // store nullptr in rhs.ptr
}
- Load the rhs pointer value,
- store it in the new object and
- store
nullptr
in the rhs object
The move constructor do not need to load the current pointer because it is usually nullptr
.
Move assignment
MyClass& operator=(MyClass&& rhs) {
auto r3 = this->ptr; // load this->ptr
this->ptr = rhs.ptr; // load rhs.ptr, store it in ptr
rhs.ptr = r3; // store rhs.ptr
return *this;
}
- Load the current pointer value,
- load the rhs pointer value,
- store the rhs in the current object and
- store the old value from step 1. in the rhs, move-from object, thus transferring the ownership and making sure it will delete it.
So move assignment looks just like swap. No self-assignment check to prevent branching.
The assignment have to make sure that the memory pointed by the previous value of the pointer is freed and the source object is in valid state. The easiest way to ensure this is to store the old pointer in the rhs object and it will delete it.
Here you can see a slightly optimized code generated by clang 5.0.0 (https://godbolt.org/g/WxGxZ4):
MyClass::MyClass(MyClass&&): # @MyClass::MyClass(MyClass&&)
mov rax, qword ptr [rsi]
mov qword ptr [rdi], rax
mov qword ptr [rsi], 0
ret
MyClass::operator=(MyClass&&): # @MyClass::operator=(MyClass&&)
mov rax, qword ptr [rdi]
mov rcx, qword ptr [rsi]
mov qword ptr [rdi], rcx
mov qword ptr [rsi], rax
mov rax, rdi
ret