Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How should I decide when it is more or less appropriate to use raw pointers?

I get the impression that Rust is intended to be used in highly safe systems. Then I noticed that raw pointers allow arbitrary pointer arithmetic, and they can cause memory safety and security issues.

like image 901
PHA Avatar asked May 07 '18 12:05

PHA


People also ask

In what kind of circumstances would you use a raw pointer instead of a smart pointer?

The rule would be this - if you know that an entity must take a certain kind of ownership of the object, always use smart pointers - the one that gives you the kind of ownership you need. If there is no notion of ownership, never use smart pointers.

Why do we need raw pointers in smart pointers?

Smart pointers are class objects that behave like raw pointers but manage objects that are new and when or whether to delete them— smart pointers automatically delete the managed object at the appropriate time.


1 Answers

Basically, a pointer is an object that refers to another object. In most programming languages (I guess) a pointer is actually just a number that refers to a memory address. Rust's raw pointers are really just that - memory addresses. There are other pointer types in Rust (& references, Box, Rc, Arc), for which the compiler can verify that the memory is valid and contains what the program thinks it contains. This is not the case for raw pointers; they can in principle point to any memory location, regardless of the content. Refer to The Book for more details.

Raw pointers can only be dereferenced inside unsafe blocks. These blocks are a way for the programmer to tell the compiler "I know better than you that this is safe and I promise not to do anything stupid".

It is generally best to avoid raw pointers if possible because the compiler cannot reason about their validity, which makes them unsafe in general. Things that make raw pointers unsafe are the potential to...

  • access a NULL pointer,
  • access a dangling (freed or invalid) pointer,
  • free a pointer multiple times,

All these points boil down to dereferencing the pointer. That is, to use the memory pointed to.

However, using raw pointers without dereferencing them is perfectly safe. This has a use case in finding out if two references point to the same object:

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

Another use case is the foreign function interface (FFI). If you wrap a C function that takes raw pointers as arguments, there is no way around providing them to the function. This is actually unsafe (as is the whole FFI business), because the function is likely to dereference the pointer. This means you are responsible for making sure the pointer is valid, stays valid, and is not freed multiple times.

Finally, raw pointers are used for optimization. For example, the slice iterator uses raw pointers as internal state. This is faster than indices because they avoid range checks during iteration. However, it is also unsafe as far as the compiler is concerned. The library author needs to pay extra attention, so using raw pointers for optimization always comes at the risk of introducing memory bugs that you normally do not have in rust.

In summary, the three main uses of raw pointers are:

  • "just numbers" - you never access the memory they point to.
  • FFI - you pass them outside Rust.
  • memory-mapped I/O - to trigger I/O actions you need to access hardware registers at fixed addresses.
  • performance - they can be faster than other options, but the compiler won't enforce safety.

As to when raw pointers should be used, the first three points are straight-forward: You will know when they apply because you have to. The last point is more subtle. As with all optimizations, only use them when the benefit outweighs the effort and risk of using them.

A counter example when not to use raw pointers is whenever the other pointer types (& references, Box, Rc, Arc) do the job.

like image 85
MB-F Avatar answered Oct 23 '22 06:10

MB-F