我该如何决定何时使用原始指针更合适?

PHA*_*PHA 6 pointers rust raw-pointer

我得到的印象是,Rust旨在用于高度安全的系统.然后我注意到原始指针允许任意指针算术,它们可能导致内存安全和安全问题.

kaz*_*ase 7

基本上,指针是引用另一个对象的对象.在大多数编程语言中(我猜)指针实际上只是一个指向内存地址的数字.Rust的原始指针实际上只是 - 内存地址.还有其他指针类型拉斯特(&引用Box,Rc,Arc),为此,编译器可以验证内存是有效的,并且包含程序认为它包含什么.原始指针不是这种情况; 无论内容如何,​​它们原则上都可以指向任何内存位置.有关详细信息,请参阅本书.

原始指针只能在unsafe块内取消引用.这些块是程序员告诉编译器的一种方式" 我比你更了解这是安全的,我保证不会做任何愚蠢的事情 ".

如果可能的话,通常最好避免使用原始指针,因为编译器无法推断其有效性,这使得它们通常不安全.使原始指针不安全的事情有可能......

  • 访问NULL指针,
  • 访问悬空(释放或无效)指针,
  • 多次释放指针,

所有这些点归结为取消引用指针.也就是说,要使用指向的内存.

但是,使用原始指针而不解除引用它们是非常安全的.这有一个用例,用于查明两个引用是否与同一个对象进行比较:

fn is_same(a: &i32, b: &i32) -> bool {
    a as *const _ == b as *const _
}
Run Code Online (Sandbox Code Playgroud)

另一个用例是外部函数接口(FFI).如果您将一个以原始指针作为参数的C函数包装起来,则无法将它们提供给该函数.这实际上是不安全的(就像整个FFI业务一样),因为该函数可能会取消引用指针.这意味着您有责任确保指针有效,保持有效,并且不会多次释放.

最后,原始指针用于优化.例如,切片迭代器使用原始指针作为内部状态.这比索引更快,因为它们避免了迭代期间的范围检查.但是,就编译器而言,它也是不安全的.库作者需要特别注意,因此使用原始指针进行优化总是存在引入通常没有生锈的内存错误的风险.

总之,原始指针的三个主要用途是:

  • "只是数字" - 你永远不会访问他们指向的记忆.
  • FFI - 你把它们传给Rust外面.
  • 内存映射I/O - 触发在固定地址访问硬件寄存器所需的I/O操作.
  • 性能 - 它们可以比其他选项更快,但编译器不会强制执行安全性.

至于何时应该使用原始指针,前两点是直截了当的:你知道它们何时适用,因为你必须这样做.最后一点更微妙.与所有优化一样,只有在利益超过使用它们的努力和风险时才使用它们.

当一个反例使用原始指针是每当其他指针类型(&引用Box,Rc,Arc)做的工作.