Confused about using weak references

Hi there - I'm confused about how to get weak references to work. I want to have a single collection of owned objects and then multiple collections of weak references to those owned objects, so that dropping the owned objects doesn't require manually removing it from all of those other collections.

But my understanding is wrong: Rust Playground

use std::collections::HashMap;
use std::rc::{Rc, Weak};
use std::vec::Vec;
fn main() {
    // the authoritive list of owned objects keyed by their ID
    let mut m = HashMap::<u32, Rc<u32>>::new();
    // new scope to ensure a doesn't live longer and thus confusing intuition
    {
        let a = Rc::new(5);
        m.insert(5, a);
    }

    // a collection of weak references to the strongly owned objects in m
    let mut col1: Vec<Weak<u32>> = vec![];
    
    // create a non-owning reference
    col1.push(Rc::downgrade(m.get(&5).unwrap()));

    // check my intuition
    let x: Vec<Option<Rc<u32>>> = col1.iter().map(|i| i.upgrade()).collect();
    println!("should be Some(5): {:?}", &x);

    // Now drop the authoritively owned object
    m.remove(&5);

    // col1 should reference the DROPPED original RC and be None
    let x: Vec<Option<Rc<u32>>> = col1.iter().map(|i| i.upgrade()).collect();
    println!("should be None: {:?}, but is Some :-(", &x);
}

This vector keeps the objects alive, as long as it's alive itself. Drop it (or wrap its creation in a block), and you'll get what you expect.

3 Likes

Gah - because the upgrade creates an owning reference - doh! Thanks!

use std::collections::HashMap;
use std::rc::{Rc, Weak};
use std::vec::Vec;
fn main() {
    // the authoritive list of owned objects keyed by their ID
    let mut m = HashMap::<u32, Rc<u32>>::new();
    // new scope to ensure a doesn't live longer and thus confusing intuition
    {
        let a = Rc::new(5);
        m.insert(5, a);
    }

    // a collection of weak references to the strongly owned objects in m
    let mut col1: Vec<Weak<u32>> = vec![];

    // create a non-owning reference
    col1.push(Rc::downgrade(m.get(&5).unwrap()));

    {
        // check my intuition
        let x: Vec<Option<Rc<u32>>> = col1.iter().map(|i| i.upgrade()).collect();
        println!("should be Some(5): {:?}", &x);
    }
    // Now drop the authoritively owned object
    m.remove(&5);

    // col1 should reference the DROPPED original RC and be None
    let x: Vec<Option<Rc<u32>>> = col1.iter().map(|i| i.upgrade()).collect();
    println!("should be None: {:?}", &x);
}

Well, that is the point of upgrade(). If you don't want to re-create an Rc from a Weak, then simply don't upgrade it.

thanks - I realised that ;-). It didn't click that the vector handing around would (of course) keep the references alive. This was all to test my intuition but I flummoxed myself with "testing" my intuition by creating that vector, which had an expected side effect.