2

Like some kind of Box that holds the reference to the value or something? I'd have to check whether the value is still alive or not before reading it, like when a Option is pattern matched.

A mock example:

struct Whatever {
    thing: AliveOrNot<i32>,
}
fn main() {
    let mut w = Whatever { thing: Holder::Empty };
    w.thing = AliveOrNot::new(100);
    match w.thing {
        Empty => println!("doesn't exist"),
        Full(value) => println!("{}", value),
    }
}

The exact case is that I'm using a sdl2 Font and I want to store instances of that struct in another struct. I don't want to do something like this because the Parent would have to live exactly as long as the Font:

struct Font<'a, 'b> {
    aa: &'a i32,
    bb: &'b i32,
}
struct Parent<'a, 'b, 'c> {
    f: &'c Font<'a, 'b>
}

What I want is for the Parent to work regardless of whether that field is still alive or not.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Pablo Tato Ramos
  • 409
  • 4
  • 18

1 Answers1

4

You may be interested in std::rc::Weak or std::sync::Weak:

use std::rc::{Rc, Weak};

struct Whatever {
    thing: Weak<i32>,
}

impl Whatever {
    fn do_it(&self) {
        match self.thing.upgrade() {
            Some(value) => println!("{}", value),
            None => println!("doesn't exist"),
        }
    }
}

fn its_dead_jim() -> Whatever {
    let owner = Rc::new(42);
    let thing = Rc::downgrade(&owner);

    let whatever = Whatever { thing };
    whatever.do_it();

    whatever
}

fn main() {
    let whatever = its_dead_jim();
    whatever.do_it();
}
42
doesn't exist

There is no way to do this in safe Rust using non-'static references. A huge point of Rust's references is that it's impossible to refer to invalid values.

  • You could leak the memory, creating a &'static i32, but that's not sustainable if you need to do this multiple times.

  • You could use unsafe code and deal with raw pointers that have no notion of lifetimes. You then assume the responsibility of ensuring you don't introduce memory unsafety.

See also:

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • How would I specify the type with the lifetimes then? Wouldn't the Parent struct have to live as long as the Font struct if I do something like https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=a596a2d92b38ee4433fc1fb0e0f9f9e5 ? – Pablo Tato Ramos Mar 03 '20 at 15:14
  • @PabloTatoRamos with that example, `Parent` would not be allowed to outlive whatever establishes the `'a` and `'b` lifetimes, [but the `Font` can be dropped](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=09ed93dad3fd8492eddc36cba07a6aef). – Shepmaster Mar 03 '20 at 15:20
  • I think we are not understanding each other. the 'a and 'b lifetimes are there because they have meaning to Font, not because they have meaning to Parent. I specifically don't want to drop Parent when those lifetimes are over. – Pablo Tato Ramos Mar 03 '20 at 15:25
  • the point is I want the Parent struct to not know if Font exists or not. I don't know how to explain it better – Pablo Tato Ramos Mar 03 '20 at 15:27
  • or rather it might know. it's just that it could be any of the two states. – Pablo Tato Ramos Mar 03 '20 at 15:28
  • I don't particularly care if the answer is to write unsafe code. I'd just like to know where to look into – Pablo Tato Ramos Mar 03 '20 at 16:00
  • 2
    @PabloTatoRamos It isn't a matter of if you can write `unsafe` code to do this - it would also be _unsound_. Even looking at a dangling pointer is undefined behaviour, so your best option is to use a `Weak`, which is specifically designed to model the idea of a reference that might not be valid anymore. – Peter Hall Mar 03 '20 at 16:48
  • 2
    @Pablo You *cannot* have an invalid reference, even in unsafe code. Creating one is instant-UB. The reason lifetimes exist is to prove this. It sounds like you have only at best a vague idea of how you want the problem to be solved; Rust does not have any mechanism that would allow a `Parent` to be informed that it should be invalidated, or indeed any mechanism that would allow a `Parent` to know that it *is* invalidated. **References are always valid.** – trent Mar 03 '20 at 16:49
  • @PeterHall I did not understand what you're trying to say. Shepmaster already told me to use Weak, it's higher up in the thread – Pablo Tato Ramos Mar 03 '20 at 17:22
  • If the answer is "it is impossible", is there a blog post or a documentation explaining why that's the case? I'm curious – Pablo Tato Ramos Mar 03 '20 at 17:30
  • @PabloTatoRamos It is impossible. I don't know about blog posts, but I think it is summed up pretty well by [trentcl's comment](https://stackoverflow.com/questions/60508705/is-there-a-way-to-have-a-struct-contain-a-reference-that-might-no-longer-be-vali/60508832?noredirect=1#comment107050937_60508832): _"You cannot have an invalid reference, even in unsafe code. Creating one is instant-UB."_ – Peter Hall Mar 03 '20 at 17:37