"cannot return value referencing local variable" when returning PhysicalDevice (Vulkano)

Viewed 543

I know this is a Rust newbie problem, but I actually can't wrap my head around it. I need to pass around a PhysicalDevice from the Vulkano library. The problem is, PhysicalDevice holds a reference:

pub struct PhysicalDevice<'a> {
    instance: &'a Arc<Instance>,
    device: usize,
}

So Rust won't compile my sacred code:

struct InstanceInfo<'a> {
    instance: Arc<Instance>,
    physical: PhysicalDevice<'a>,
    // ...
}

// ...

fn instantiate() -> InstanceInfo<'static> {
    // ...
    let instance = Instance::new(None, &required_extensions, None).unwrap();
    
    let physical = PhysicalDevice::enumerate(&instance).next().unwrap();
    // ...
    InstanceInfo { // cannot return value referencing local blah
        instance,
        physical,
        // ...
    }
}

How can I work around this?

1 Answers

So the reason for the error message is that instance is a local variable in your instantiate function. Because you aren't moving its ownership to the return value, it will be dropped at the end of the function.

But then if it gets dropped, any reference to it would be invalid. That's why Rust doesn't let you return something holding a reference to the local variable.

First, your struct is redundant, because PhysicalDevice already holds a reference for the instance. Even without the local variable problem, I think you'd run into an ownership problem.

Second, let's say you rewrite and get rid of your InstanceInfo struct and instead you want to just return a PhysicalDevice<'static>. Well if that's what you promise to the compiler, then you have to make sure that the instance you create will live for as long as the program lives.

You can do that either by having instance be a static variable of your module, or by creating it at the very beginning of the program and then simply pass a reference ot it around.

For example

fn main() {
 let instance = Instance::new(None, blablabla).unwrap();
 
 let physical = instantiate(&instance);
}

fn instantiate<'a>(instance: &'a Arc<Instance>) -> PhysicalDevice<'a> {
  PhysicalDevice::enumerate(instance).next().unwrap();
}

Might have gotten a & wrong here or there, but this is the gist of it.

If you have to put everything into an extra struct, then I think what you want to do is to clone the Arc instead of just moving it.

Related