`std :: mem :: swap`如何工作?

Kap*_*chu 5 memory swap rust

在相同类型的两个可变位置交换值,而不取消初始化或复制任何一个.

use std::mem;

let x = &mut 5;
let y = &mut 42;

mem::swap(x, y);

assert_eq!(42, *x);
assert_eq!(5, *y);
Run Code Online (Sandbox Code Playgroud)

(来自正式的Rust doc)

如何在不复制的情况下交换两个值?价值42是怎么y来的x?这不应该是可能的.

Lev*_*ans 6

该函数实际上在内部进行复制:这是从文档中提取的源代码:

pub fn swap<T>(x: &mut T, y: &mut T) {
    unsafe {
        // Give ourselves some scratch space to work with
        let mut t: T = uninitialized();

        // Perform the swap, `&mut` pointers never alias
        ptr::copy_nonoverlapping(&*x, &mut t, 1);
        ptr::copy_nonoverlapping(&*y, x, 1);
        ptr::copy_nonoverlapping(&t, y, 1);

        // y and t now point to the same thing,
        // but we need to completely forget `t`
        // because it's no longer relevant.
        forget(t);
    }
}
Run Code Online (Sandbox Code Playgroud)

  • "生锈级别复制"(重复值,需要两次免费)和实现级别复制之间存在差异.在rust语义中,这里没有副本,这两个值只是移动. (8认同)

She*_*ter 5

在以前的答案是语义正确的,但在具体细节已经过时。

从逻辑上讲,交换两个值的工作原理是将值 A 读入一个临时位置,将 B 复制到 A 的顶部,然后将临时值写回 B。在短时间内,相同的值在内存中存在两次。这就是为什么这些功能的实现需要unsafe代码,因为只有人类才能保证 Rust 的安全要求得到维护。

从 Rust 1.43.0 开始,mem::swap实现为:

pub fn swap<T>(x: &mut T, y: &mut T) {
    // SAFETY: the raw pointers have been created from safe mutable references satisfying all the
    // constraints on `ptr::swap_nonoverlapping_one`
    unsafe {
        ptr::swap_nonoverlapping_one(x, y);
    }
}
Run Code Online (Sandbox Code Playgroud)

swap_nonoverlapping_one是私有的,但它的实现是:

pub(crate) unsafe fn swap_nonoverlapping_one<T>(x: *mut T, y: *mut T) {
    // For types smaller than the block optimization below,
    // just swap directly to avoid pessimizing codegen.
    if mem::size_of::<T>() < 32 {
        let z = read(x);
        copy_nonoverlapping(y, x, 1);
        write(y, z);
    } else {
        swap_nonoverlapping(x, y, 1);
    }
}
Run Code Online (Sandbox Code Playgroud)

您可以查看文档ptr::copy_nonoverlapping和ptr::swap_nonoverlapping。后者基本上是针对较大值的复制的高度优化版本。