答案here表示,对于任何拥有一个拥有指针的对象。
Move constructor: 1 load and 2 stores.
Move assignment: 2 loads and 2 stores.
我的问题是,这是如何运作的。我的想法
MyClass& operator=(MyClass&& rhs);//lhs is this
首先必须加载lhs
和rhs
。然后rhs
存储到lhs
。这占了两个负载和一个商店。 rhs
是否仍然存回,即使没有更改,它是一个右值?
MyClass(MyClass&& rhs);
此时只有rhs
加载到寄存器中。然后将其存储到lhs
。那是一个负载和一个商店。什么比?同样,我错过了一家商店,如上所述。
答案 0 :(得分:2)
正如在具有单个拥有指针的类的优化案例的链接答案中所指出的那样:
MyClass(MyClass&& rhs):
ptr(rhs.ptr) { // load rhs.ptr, store it in ptr
rhs.ptr = nullptr; // store nullptr in rhs.ptr
}
nullptr
存储在rhs对象移动构造函数不需要加载当前指针,因为它通常是nullptr
。
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;
}
所以移动任务看起来就像交换。没有自我分配检查以防止分支。
赋值必须确保释放指针前一个值指向的内存,并且源对象处于有效状态。确保这一点的最简单方法是将旧指针存储在rhs对象中,它将删除它。
在这里,您可以看到由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