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

Yan*_*Yan 4 rust

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

struct Point {
    x: i32,
    y: i32,
}

fn main() {
    let p = Point { x: 1, y: 1 };
    let q = p;
}
Run Code Online (Sandbox Code Playgroud)

当 时let q = p;,数据(大小为 8 字节)是否会从一个内存地址复制到另一个内存地址?由于p已移至此处,因此无法再使用,我认为最好使q' 的底层内存地址等于p' 。换句话说,我认为机器代码中不复制任何内容是可以的。

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

Sve*_*ach 8

\n

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

\n
\n

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

\n

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

\n
\n

如果会,为什么?

\n
\n

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

\n

以下是编译器可能无法将源内存重用于目标内存的一些说明:

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

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

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

    \n
  • \n
\n

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

\n