`std::mem::swap` 是如何工作的?
How does `std::mem::swap` work?
Swap the values at two mutable locations of the same type, without deinitialising or copying either one.
use std::mem;
let x = &mut 5;
let y = &mut 42;
mem::swap(x, y);
assert_eq!(42, *x);
assert_eq!(5, *y);
(来自 offical Rust doc)
如何在不复制的情况下交换两个值?值 42
如何从 y
变为 x
?这应该是不可能的。
该函数实际上在内部制作了一个副本:这是从文档中提取的源代码:
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);
}
}
在语义上是正确的,但在确切的细节上已经过时了。
从逻辑上讲,交换两个值的工作原理是将值 A 读入临时位置,将 B 复制到 A 之上,然后将临时值写回 B。有一个短暂的时期,相同的值在内存中存在两次。这就是为什么 实现 这些函数需要 unsafe
代码,因为只有人类才能保证 Rust 的安全要求得到遵守。
从 Rust 1.43.0 开始,mem::swap
is implemented as:
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);
}
}
swap_nonoverlapping_one
是私有的,但是 its implementation 是:
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);
}
}
您可以查看 ptr::copy_nonoverlapping
and ptr::swap_nonoverlapping
的文档。后者基本上是针对较大值复制的高度优化版本。
Swap the values at two mutable locations of the same type, without deinitialising or copying either one.
use std::mem; let x = &mut 5; let y = &mut 42; mem::swap(x, y); assert_eq!(42, *x); assert_eq!(5, *y);
(来自 offical Rust doc)
如何在不复制的情况下交换两个值?值 42
如何从 y
变为 x
?这应该是不可能的。
该函数实际上在内部制作了一个副本:这是从文档中提取的源代码:
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);
}
}
从逻辑上讲,交换两个值的工作原理是将值 A 读入临时位置,将 B 复制到 A 之上,然后将临时值写回 B。有一个短暂的时期,相同的值在内存中存在两次。这就是为什么 实现 这些函数需要 unsafe
代码,因为只有人类才能保证 Rust 的安全要求得到遵守。
从 Rust 1.43.0 开始,mem::swap
is implemented as:
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);
}
}
swap_nonoverlapping_one
是私有的,但是 its implementation 是:
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);
}
}
您可以查看 ptr::copy_nonoverlapping
and ptr::swap_nonoverlapping
的文档。后者基本上是针对较大值复制的高度优化版本。