John Difool
John Difool

Reputation: 5732

temporary value dropped while borrowed

I am getting this issue, as the variables I am deconstructing are borrowed(?) and can't be used in another method. This sounds like a very typical use case but I am not sure how to solve it.

`➜  hello_cargo git:(master) ✗ cargo build
   Compiling hello_cargo v0.1.0 (/Users/johnny/Projects/hello_cargo)
error[E0716]: temporary value dropped while borrowed
  --> src/main.rs:24:39
   |
24 |         let DBAndCFs { db: _, cfs } = self.db.lock().as_ref().unwrap();
   |                                       ^^^^^^^^^^^^^^                  - temporary value is freed at the end of this statement
   |                                       |
   |                                       creates a temporary which is freed while still in use
25 |         cfs.len()
   |         --------- borrow later used here
   |
   = note: consider using a `let` binding to create a longer lived value
`

Here is the code that generates this issue:

    use parking_lot::Mutex;
    
    struct CF {
        inner: *mut i32,
    }
    
    struct DBAndCFs {
        db: i32,
        cfs: Vec<CF>,
    }
    
    struct DB {
        db: Mutex<Option<DBAndCFs>>,
    }
    
    impl DB {
    
        pub fn open() -> DB {
            DB {
                db: Mutex::new(Some(DBAndCFs{ db: 0, cfs: Vec::new() } )),
            }
        }
        pub fn get(&self) -> usize {
            let DBAndCFs { db: _, cfs } = self.db.lock().as_ref().unwrap();
            cfs.len()
        }
    }
    fn main() {
        let db = DB::open();
        print!("{}", db.get());
    }

Upvotes: 0

Views: 9096

Answers (1)

Caesar
Caesar

Reputation: 8544

temporary value is freed at the end of this statement
consider using a let binding to create a longer lived value

So the compiler is telling you that self.db.lock() is a temporary that gets dropped too early, and that you can extend its lifetime with a let binding. The advice is so precise that you could even follow it without knowing what's going on:

let db = self.db.lock();
let DBAndCFs { db: _, cfs } = db.as_ref().unwrap();
cfs.len()

The reason here is that self.db.lock() creates a mutex guard, that keeps the mutex locked until it is dropped. If you give it a variable to live in, that variable will exist to the end of the scope (the next }), and the guard won't be dropped long enough for you to call cfs.len(). If you don't give it a variable to live in, it will live as a temporary, until the next ;. Since you're trying to keep a reference to cfs beyond that ;, you'd have a reference to something protected by a mutex without the mutex being locked, which can't be allowed.

The other way to do what you want to call len before your temporary lock guard is dropped:

self.db.lock().as_ref().unwrap().cfs.len()

Upvotes: 7

Related Questions