移动变量时,数据会被逐字节复制吗



我对rust是新手,我想知道移动变量时到底会发生什么。

struct Point {
x: i32,
y: i32,
}
fn main() {
let p = Point { x: 1, y: 1 };
let q = p;
}

let q = p;时,数据(大小为8字节(是否会从一个内存地址复制到另一个?由于p被移到了这里,因此它不能再使用了,我认为让q的底层内存地址等于p的地址是好的。换句话说,我认为在机器代码中不复制任何东西是可以的。

所以我的问题是:在移动变量时,数据会被逐字节复制吗?如果会,为什么?

[W]在移动变量时是否会逐字节复制数据?

一般来说,是的。要移动值,Rust只需执行逐位复制。如果该值不是Copy,则移动后将不再使用源。如果值为Copy,则可以同时使用源和目标。

然而,在许多情况下,编译器后端可以通过证明没有副本的代码是相同的来消除副本。这种优化完全发生在LLVM中。在您的示例中,LLVM IR仍然包含移动数据的指令,但生成的代码即使在调试模式下也不包含移动。

如果会,为什么?

编译器无法为源和目标使用相同内存的原因有很多。在您的示例中,在同一堆栈框架中有两个变量,很容易看出不需要移动,但代码无论如何都有点毫无意义(尽管有时人们确实会在函数中移动值,使变量不可变(。

以下只是编译器可能无法为目标重用源内存的几个示例:

  • 源值可能在堆栈上,而目标在堆上,反之亦然。语句let b = Box::new(3);将把值3从堆栈移动到堆';let i = *b;将把它从堆移回堆栈。编译器仍然有可能消除这些移动,例如,通过立即将常量3写入堆,而无需先将其写入堆栈。

  • 当跨函数移动值时,源和目标可能位于不同的堆栈帧上,例如,当将值传递到函数中时,或当从函数返回值时。

  • 源值和目标值可能存储在结构字段中,因此它们需要在结构中具有正确的偏移量。

这些只是几个例子。结论是,一般来说,一次移动可能会导致按位复制。不过,请记住,按位复制非常便宜,而且优化器通常做得很好,所以只有在确实存在性能瓶颈的情况下,才应该担心这一点。

最新更新