如何使用(不安全)别名?

Kor*_*nel 5 strict-aliasing rust borrow-checker

Rust有严格的别名规则.但是,如果"我知道我在做什么",我可以解决它们吗?

我正在尝试转换为Rust一个C函数,它通过从输入缓冲区读取并写入目标缓冲区来执行复杂的操作,但它有一个聪明的优化,允许输入和输出缓冲区相同:

foo(src, dst); // result is written to dst
foo(buf, buf); // legal in C, does the operation in-place
Run Code Online (Sandbox Code Playgroud)

为了这个问题,让我们说它是这样的:

void inplace(char *src, char *dst, int len) {
   for(int i=0; i < len-1; i++) {
      dst[i] = src[i+1] * 2; // algorithm works even if src == dst
   }
}
Run Code Online (Sandbox Code Playgroud)

生锈的安全集我得有功能的两个几乎复制和粘贴的版本fn(&mut)fn(&, &mut).

有没有办法欺骗Rust以获得对同一缓冲区的可变和不可变引用?

Ste*_*nik 5

Rust 不允许您对可变性进行参数化,不。

理论上,您可以编写一些给指针别名的不安全代码,但您必须直接使用原始指针。

&mut意味着该指针没有别名,优化器会这样对待它。使用一个原始指针和一个&mut指针仍然会导致问题。


Mat*_* M. 5

不,你不能在安全的Rust中这样做.如果您愿意,可以使用不安全的代码来解决别名限制......

但它有一个聪明的优化,允许输入和输出缓冲区相同

你称之为优化,我称之为悲观.

当两个缓冲区保证不相同时,优化器可以对代码进行矢量化.这意味着循环的比较少4倍或8倍,大大加快了大输入的执行速度.

然而,在没有别名信息的情况下,它必须悲观地假设输入可能是别名的,因此不能进行这样的优化.更糟的是,不知道怎么样,他们的别名,它甚至不知道是否&dst[i] == &src[i-1]&dst[i] == &src[i]&dst[i] == &src[i+1]; 这意味着预取等等......


但是,在安全的Rust中,可以获得此信息.它会强制您编写两个例程(一个用于单个输入,一个用于两个输入),但两者都可以相应地进行优化.


Fra*_*gné 2

为了使用原始指针,您的 main 函数必须使用不安全代码来实现。原始指针允许您绕过 Rust 的别名规则。然后,您可以使用两个函数作为此不安全实现的安全 fa\xc3\xa7ades。

\n\n
unsafe fn foo(src: *const u8, dst: *mut u8, len: usize) {\n    for i in 0..len - 1 {\n        *dst.offset(i as isize) = *src.offset(i as isize + 1) * 2;\n    }\n}\n\nfn foo_inplace(buf: &mut [u8]) {\n    unsafe { foo(buf.as_ptr(), buf.as_mut_ptr(), buf.len()) }\n}\n\nfn foo_separate(src: &[u8], dst: &mut [u8]) {\n    assert!(src.len() == dst.len());\n    unsafe { foo(src.as_ptr(), dst.as_mut_ptr(), src.len()) }\n}\n\nfn main() {\n    let src = &[0, 1, 2, 3, 4, 5];\n    let dst = &mut [0, 0, 0, 0, 0, 0];\n\n    let buf = &mut [11, 22, 33, 44, 55, 66];\n\n    foo_separate(src, dst);\n    foo_inplace(buf);\n\n    println!("src: {:?}", src);\n    println!("dst: {:?}", dst);\n    println!("buf: {:?}", buf);\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

as_ptr()as_mut_ptr()和是切片len()上的方法。

\n