2

Rust 语言不允许不安全的代码从原始指针后面移出非复制类型,报告以下程序的编译错误:

use std::cell::UnsafeCell;

struct NonCopyType(u32);

fn main() {
    let unsafe_cell = UnsafeCell::new(NonCopyType(123));
    
    let ptr = unsafe_cell.get();

    // Disallowed, but the code will never access
    // the uninitialized unsafe cell after this.
    let _ = unsafe { *ptr };
}

编译错误:

error[E0507]: cannot move out of `*ptr` which is behind a raw pointer
  --> src/main.rs:12:22
   |
12 |     let _ = unsafe { *ptr };
   |                      ^^^^ move occurs because `*ptr` has type `NonCopyType`, which does not implement the `Copy` trait

For more information about this error, try `rustc --explain E0507`.
error: could not compile `playground` due to previous error

该错误消息的动机是什么?是因为从原始指针后面移出非复制类型很容易出错,即使开发人员声明他足够专家编写不安全的代码?或者上面的程序中是否有一些我遗漏的未定义行为?

4

1 回答 1

1

该错误消息的动机是什么?

为了将解引用运算符应用于原始指针,程序员必须坚持的安全不变量只是指针是可解引用的。在必须支持额外保证的情况下(例如,不再使用引用的值),Rust 要求使用具有这些要求的某些方法来代替。

在这种情况下,正如 loganfsmyth 评论的那样,有std::ptr::read; 或者原始指针类型本身存在固有read方法。因此:

use std::cell::UnsafeCell;

struct NonCopyType(u32);

fn main() {
    let unsafe_cell = UnsafeCell::new(NonCopyType(123));
    let ptr = unsafe_cell.get();
    let _ = unsafe { ptr.read() };
}

是因为从原始指针后面移出非复制类型很容易出错,即使开发人员声明他足够专家编写不安全的代码?

unsafe与专业知识无关,与承担责任维护某些不变量有关,否则编译器会为您检查这些不变量;明确每种方法需要维护的不变量,以及每个调用者都维护的不变量,这绝对是实现这一点的关键。

我想,Rust 可能已经重载了解引用运算符的安全要求,因此程序员需要根据上下文维护不同的不变量。但这将是一把可怕的枪,并且对于编写代码的人和后来阅读它的任何人来说,对代码的推理都非常痛苦。

于 2022-01-12T19:48:06.953 回答