Why should I write lifetime when using raw pointer to structure with lifetime?

Let's assume I have a structure with containing a reference:

struct A<'a> {
    reference_to_number: &'a i32,
}

Since it contains reference, I should add lifetime to structure.

Now I have a structure that have reference to A:

struct B<'b, 'a: 'b> {
    reference_to_a: &'b A<'a>,
}

Well, now I have lifetime of reference 'b (that should outlive structure itself) and lifetime of a referenced structure 'a (that should outlive reference).

Now for a reason beyond the scope if this thread I want to use raw pointer:

struct B<'a> {
    raw_pointer_to_a: *const A<'a>,
}

For what reason should I use lifetime 'a? Since it is raw pointer I have no idea about lifetime of A. A can be dropped, and I will get null pointer, but since I use raw pointer shouldn't I be allowed to do so? Why rust enforces me to use lifetime?

A<'a> says that an instance of A is valid over some lifetime 'a. This is the case whether you have a reference to an A or own an A. In other words, that lifetime parameter is somewhat orthogonal to the lifetime of a reference to A<a'>.

If you want to erase the lifetime for some reason, however, you can transmute the A<'a> to A<'static> and get rid of the lifetime parameter on B. But this opens you up to more unsafety than just raw_pointer_to_a pointing at null.

Note also that:

struct B<'a> {
    ptr: &'a A<'a>
}

is perfectly fine if A is variant - you don't need the two lifetime parameters.

2 Likes

For what reason should I use lifetime 'a? Since it is raw pointer I have no idea about lifetime of A. A can be dropped, and I will get null pointer, but since I use raw pointer shouldn’t I be allowed to do so? Why rust enforces me to use lifetime?

In all fairness, the lifetimes embedded in a raw pointer don't mean much for the vast majority of code working with a raw pointer. But they do matter at the point in your code where you dereference it.

  • Reading a *const A<'a> will produce an A<'a>.
  • This may invoke Undefined Behavior if said A<'a> will contain e.g. a &'a T that may dangle for some portion of the lifetime 'a.
  • It follows that, before dereferencing a type that contains lifetimes, you must know that the lifetimes are valid.

In the vast majority of unsafe code, people are dealing with something like some T<'a> that is valid for the lifetime 'a (but not some longer lifetime like static), and so it is very helpful that the default behavior of rust is to carry these lifetimes into the pointer type. This helps catch some avoidable mistakes that people might make in unsafe code.

In your case, however, when carrying these lifetimes is not helpful, you can cast them away as suggested by @vitalyd

2 Likes