temporary value dropped while borrowed - rust

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());
}

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()

Related

Why rust requires manual drop of a variable in this case?

Following code gives error if cnode isn't manually dropped after each iteration. As it's going out of scope, it should be automatically dropped, and I think there is no chance of outlive the borrowed value. But it complains with error borrowed value does not live long enough.
#[cfg(feature = "localrun")]
#[derive(Debug, PartialEq, Eq)]
pub struct TreeNode {
pub val: i32,
pub left: Option<Rc<RefCell<TreeNode>>>,
pub right: Option<Rc<RefCell<TreeNode>>>,
}
#[cfg(feature = "localrun")]
impl TreeNode {
#[inline]
pub fn new(val: i32) -> Self {
TreeNode {
val,
left: None,
right: None
}
}
}
// use std::borrow::Borrow;
use std::rc::Rc;
use std::cell::RefCell;
impl Solution {
pub fn max_depth(root: Option<Rc<RefCell<TreeNode>>>) -> i32 {
let mut depth = 0;
let mut vec = vec![];
if let Some(vnode) = &root {
vec.push(vnode.clone());
}
while !vec.is_empty() {
let mut size = vec.len();
while size > 0 {
size -= 1;
let cnode = vec.pop().unwrap();
if let Some(lnode) = cnode.borrow().left.as_ref() {
vec.push(lnode.clone());
}
if let Some(rnode) = cnode.borrow().right.as_ref() {
vec.push(rnode.clone());
}
// drop(cnode); // <---- Uncommenting This fixes the error though
}
}
unimplemented!()
}
}
#[cfg(feature = "localrun")]
struct Solution{}
Edit: Full error msg:
error[E0597]: `cnode` does not live long enough
--> src/w35_w36_easy/n104.rs:105:30
|
105 | if let Some(rnode) = cnode.borrow().right.as_ref() {
| ^^^^^^^^^^^^^^
| |
| borrowed value does not live long enough
| a temporary with access to the borrow is created here ...
...
109 | }
| -
| |
| `cnode` dropped here while still borrowed
| ... and the borrow might be used here, when that temporary is dropped and runs the destructor for type `Ref<'_, TreeNode>`
|
help: consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped
|
107 | };
| +
I just noticed the helpful error message from compiler. It says to add a semicolon after if block. Actually it fixed the error! Though I'm not sure why semicolon made the difference.
This is actually quite interesting, but requires delving a little more deeply than you might expect.
A while loop is, like most things in Rust, an expression—which is to say that the loop itself evaluates to some value (currently it's always of unit type (), although that could change in the future) and it can therefore be used in expression position, such as on the right hand side of an assignment:
let _: () = while false {};
The block of a while loop is also an expression (albeit one that must also always be of unit type); this value comes from the final expression in the block—which, in your case, is the final if let:
let _: () = if let Some(rnode) = cnode.borrow().right.as_ref() {
vec.push(rnode.clone());
};
The borrow of cnode continues to the end of this expression. Since the expression is evaluated as that of the while loop's block, which is evaluated as that of the while loop expression itself, it actually lives until the while loop expression is evaluated (i.e. the while loop terminates). But your borrow of cnode must not live that long, because subsequent iterations of the loop may need to borrow it again! Hence the error, and the suggestion to add a semicolon at the end of the if let expression (thus converting it into a statement and terminating the borrow of cnode before the end of the while loop block):
if let Some(rnode) = cnode.borrow().right.as_ref() {
vec.push(rnode.clone());
};
Perhaps Rust could/should be more intelligent here, and recognise the borrow cannot possibly be required for so long, but no doubt that would add considerable additional complexity and may make it harder to introduce future changes to the language in a backwards-compatible way.

Error Message Unclear: returns a value referencing data owned by the current function

I do not understand the error message I am getting for the following code.
use std::collections::HashMap;
use std::rc::Weak;
struct ThingPool {
thing_map: HashMap<String, Thing>,
}
impl ThingPool {
pub fn get(&self, key: &str) -> Option<&Thing> {
self.thing_map.get(key)
}
}
struct Thing {
pool: Weak<RefCell<ThingPool>>,
key: String,
parent_key: String,
}
impl Thing {
pub fn parent(&self) -> Option<&Thing> {
let pool = &*self
.pool
.upgrade()
.expect("FATAL: ThingPool no longer exists")
.borrow();
pool.get(&self.parent_key)
}
}
fn main() {
// ...
}
I have a recursive data structure of Things, and I am trying to write a method that looks up the parent of a particular Thing in the ThingPool based on its key. The error message I am getting is:
--> src/main.rs:30:9
|
24 | let pool = &*self
| ______________________-
25 | | .pool
26 | | .upgrade()
27 | | .expect("FATAL: ThingPool no longer exists")
28 | | .borrow();
| |_____________________- temporary value created here
29 |
30 | pool.get(&self.parent_key)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ returns a value referencing data owned by the current function
I understand that I cannot return a reference to a local value, but I do not understand what the local value is in this case. What is the "data owned by the current function"? The value I am returning is a value of the HashMap in the ThingPool. I am not copying the pool and therefore the HashMap and therewith the value should not be local to the function. What am I missing?
When you call upgrade().expect("..."), that creates a new Rc that is owned by the current function. When you borrow out of the Rc, that reference cannot outlive the Rc you just created: when the Rc is dropped, it will decrement the reference count, potentially deallocating the pool and leaving any references invalid. Currently, it is dropped when you leave the function, but the function still returns a reference to its contents.
Breaking up the chain of calls helps a little bit.
pub fn parent(&self) -> Option<&Thing> {
let pool_rc = self
.pool
.upgrade()
.expect("FATAL: ThingPool no longer exists");
let pool_ref = pool_rc.borrow();
let parent_ref = pool_ref.get(&self.parent_key);
return parent_ref;
}
pool_rc is the Rc pointer. It doesn't get returned, so it's a local that must be dropped at the end of the function call.
pool_ref is a reference to the pool. It doesn't know anything about the reference count, and it's relying on pool_rc to increment the count before it starts and decrement the count after it ends.
parent_ref is in the same pickle as pool_ref. It doesn't know about the reference count, and is relying on pool_rc stick around until after parent_ref expires so that pool_rc does not decrement the reference count while parent_ref needs access to the pool.
When you return parent_ref you are trying to make it outlive pool_rc, which could cause issues.
Here's an example of what could go wrong if this function was allowed:
There is some external Rc on the pool, so the reference count on the pool is 1.
You run Thing::parent, returning a reference to an item in the pool, but because the Rc to the pool is dropped when the function ends, the reference count on the pool is still 1.
That external Rc is dropped, taking the refcount to 0 and deallocating the pool.
You use the reference returned from parent, which refers to the already-deallocated memory.
You might be able to find some solution where you return a Rc to the pool alongside the reference to the parent, guaranteeing that it exists. However, I would advocate a different strategy: rather than hiding the fact that there is a pool, explicitly embrace it. Moving the parent call into the ThingPool makes the ownership dynamics clear.
use std::collections::HashMap;
struct ThingPool {
thing_map: HashMap<String, Thing>,
}
impl ThingPool {
pub fn get(&self, key: &str) -> Option<&Thing> {
self.thing_map.get(key)
}
pub fn parent(&self, key: &str) -> Option<&Thing> {
self.get(key).and_then(|thing| self.get(&thing.parent_key))
}
}
struct Thing {
key: String,
parent_key: String,
}

Return Ref to something inside of Rc<RefCell<>> without Ref::map

Working code first:
use std::cell::{Ref, RefCell};
use std::rc::Rc;
struct ValueHolder {
value: i32
}
fn give_value(wrapped: &Rc<RefCell<ValueHolder>>) -> Ref<i32> {
Ref::map(
(**wrapped).borrow(),
|borrowed| { &(*borrowed).value },
)
}
fn main() {
println!("Our value: {}", *give_value(
&Rc::new(RefCell::new(ValueHolder { value: 1337 }))
));
}
The relevant part is the give_value function.
I want to return a Ref to something inside a Rc<RefCell<>>, in this case a value inside of a struct.
That works just fine, but since I just started to learn Rust, I wonder, how I could achieve the same thing without using Ref::map.
The "naive" approach:
fn give_value(wrapped: &Rc<RefCell<ValueHolder>>) -> &i32 {
&(*(**wrapped).borrow()).value
}
fails for obvious reasons:
error[E0515]: cannot return value referencing temporary value
--> src/bin/rust_example.rs:9:5
|
9 | &(*(**wrapped).borrow()).value
| ^^^--------------------^^^^^^^
| | |
| | temporary value created here
| returns a value referencing data owned by the current function
So my question is: How can I recreate what the Ref::map function does by myself?
You can't. RefCell requires that Ref be used whenever the value is used, so it knows when it should allow a borrow. When the Ref gets dropped, it signals to the RefCell that it can decrease the borrow count, and if the borrow count is 0, then a mutable borrow can happen. Being able to obtain a reference to the internal data that doesn't borrow the Ref (note that a reference you can return from a function cannot borrow the Ref otherwise you'd be referencing a temporary) would be problematic, because then the Ref could get dropped and the RefCell thinks that it can lend out a mutable borrow, but there's still an immutable borrow to the data. The source code for Ref::map is:
pub fn map<U: ?Sized, F>(orig: Ref<'b, T>, f: F) -> Ref<'b, U>
where
F: FnOnce(&T) -> &U,
{
Ref { value: f(orig.value), borrow: orig.borrow }
}
which uses private fields that you can't access. So, no, you cannot recreate Ref::map yourself.

Storing a boxed closure which references an object in that object

I'm trying to implement a console system for the game I'm writing and have found a fairly simple system: I define a Console object that stores commands as boxed closures (specifically Box<FnMut + 'a> for some 'a). This works for any component of the engine so long as the Console is created before anything else.
Unfortunately, this prevents me from adding commands that modify the Console itself, which means I can't create commands that simply print text or define other variables or commands. I've written a small example that replicates the error:
use std::cell::Cell;
struct Console<'a> {
cmds: Vec<Box<FnMut() + 'a>>,
}
impl<'a> Console<'a> {
pub fn println<S>(&self, msg: S)
where S: AsRef<str>
{
println!("{}", msg.as_ref());
}
pub fn add_cmd(&mut self, cmd: Box<FnMut() + 'a>) {
self.cmds.push(cmd);
}
}
struct Example {
val: Cell<i32>,
}
fn main() {
let ex = Example {
val: Cell::new(0),
};
let mut con = Console {
cmds: Vec::new(),
};
// this works
con.add_cmd(Box::new(|| ex.val.set(5)));
(con.cmds[0])();
// this doesn't
let cmd = Box::new(|| con.println("Hello, world!"));
con.add_cmd(cmd);
(con.cmds[1])();
}
And the error:
error: `con` does not live long enough
--> console.rs:34:31
|
34 | let cmd = Box::new(|| con.println("Hello, world!"));
| -- ^^^ does not live long enough
| |
| capture occurs here
35 | con.add_cmd(cmd);
36 | }
| - borrowed value dropped before borrower
|
= note: values in a scope are dropped in the opposite order they are created
error: aborting due to previous error
Is there a workaround for this, or a better system I should look into? This is on rustc 1.18.0-nightly (53f4bc311 2017-04-07).
This is one of those fairly tricky resource borrowing conundrums that the compiler could not allow. Basically, we have a Console that owns multiple closures, which in turn capture an immutable reference to the same console. This means two constraints:
Since Console owns the closures, they will live for as long as the console itself, and the inner vector will drop them right after Console is dropped.
At the same time, each closure must not outlive Console, because otherwise we would end up with dangling references to the console.
It may seem harmless from the fact that the console and respective closures go out of scope at once. However, the drop method follows a strict order here: first the console, then the closures.
Not to mention of course, that if you wish for closures to freely apply modifications to the console without interior mutability, you would have to mutably borrow it, which cannot be done over multiple closures.
An approach to solving the problem is to separate the two: let the console not own the closures, instead having them in a separate registry, and let the closures only borrow the console when calling the closure.
This can be done by passing the console as an argument to the closures and moving the closure vector to another object (Playground):
use std::cell::Cell;
struct CommandRegistry<'a> {
cmds: Vec<Box<Fn(&mut Console) + 'a>>,
}
impl<'a> CommandRegistry<'a> {
pub fn add_cmd(&mut self, cmd: Box<Fn(&mut Console) + 'a>) {
self.cmds.push(cmd);
}
}
struct Console {
}
impl Console {
pub fn println<S>(&mut self, msg: S)
where S: AsRef<str>
{
println!("{}", msg.as_ref());
}
}
struct Example {
val: Cell<i32>,
}
fn main() {
let ex = Example {
val: Cell::new(0),
};
let mut reg = CommandRegistry{ cmds: Vec::new() };
let mut con = Console {};
// this works
reg.add_cmd(Box::new(|_: &mut Console| ex.val.set(5)));
(reg.cmds[0])(&mut con);
// and so does this now!
let cmd = Box::new(|c: &mut Console| c.println("Hello, world!"));
reg.add_cmd(cmd);
(reg.cmds[1])(&mut con);
}
I also took the liberty of making closures accept a mutable reference. No conflicts emerge here because we are no longer borrowing the console that was already borrowed when fetching the borrowing closure. This way, the closures can also outlive the console.

How to avoid mutex borrowing problems when using it's guard

I want my method of struct to perform in a synchronized way. I wanted to do this by using Mutex (Playground):
use std::sync::Mutex;
use std::collections::BTreeMap;
pub struct A {
map: BTreeMap<String, String>,
mutex: Mutex<()>,
}
impl A {
pub fn new() -> A {
A {
map: BTreeMap::new(),
mutex: Mutex::new(()),
}
}
}
impl A {
fn synchronized_call(&mut self) {
let mutex_guard_res = self.mutex.try_lock();
if mutex_guard_res.is_err() {
return
}
let mut _mutex_guard = mutex_guard_res.unwrap(); // safe because of check above
let mut lambda = |text: String| {
let _ = self.map.insert("hello".to_owned(),
"d".to_owned());
};
lambda("dd".to_owned());
}
}
Error message:
error[E0500]: closure requires unique access to `self` but `self.mutex` is already borrowed
--> <anon>:23:26
|
18 | let mutex_guard_res = self.mutex.try_lock();
| ---------- borrow occurs here
...
23 | let mut lambda = |text: String| {
| ^^^^^^^^^^^^^^ closure construction occurs here
24 | if let Some(m) = self.map.get(&text) {
| ---- borrow occurs due to use of `self` in closure
...
31 | }
| - borrow ends here
As I understand when we borrow anything from the struct we are unable to use other struct's fields till our borrow is finished. But how can I do method synchronization then?
The closure needs a mutable reference to the self.map in order to insert something into it. But closure capturing works with whole bindings only. This means, that if you say self.map, the closure attempts to capture self, not self.map. And self can't be mutably borrowed/captured, because parts of self are already immutably borrowed.
We can solve this closure-capturing problem by introducing a new binding for the map alone such that the closure is able to capture it (Playground):
let mm = &mut self.map;
let mut lambda = |text: String| {
let _ = mm.insert("hello".to_owned(), text);
};
lambda("dd".to_owned());
However, there is something you overlooked: since synchronized_call() accepts &mut self, you don't need the mutex! Why? Mutable references are also called exclusive references, because the compiler can assure at compile time that there is only one such mutable reference at any given time.
Therefore you statically know, that there is at most one instance of synchronized_call() running on one specific object at any given time, if the function is not recursive (calls itself).
If you have mutable access to a mutex, you know that the mutex is unlocked. See the Mutex::get_mut() method for more explanation. Isn't that amazing?
Rust mutexes do not work the way you are trying to use them. In Rust, a mutex protects specific data relying on the borrow-checking mechanism used elsewhere in the language. As a consequence, declaring a field Mutex<()> doesn't make sense, because it is protecting read-write access to the () unit object that has no values to mutate.
As Lukas explained, your call_synchronized as declared doesn't need to do synchronization because its signature already requests an exclusive (mutable) reference to self, which prevents it from being invoked from multiple threads on the same object. In other words, you need to change the signature of call_synchronized because the current one does not match the functionality it is intended to provide.
call_synchronized needs to accept a shared reference to self, which will signal to Rust that it can be called from multiple threads in the first place. Inside call_synchronized a call to Mutex::lock will simultaneously lock the mutex and provide a mutable reference to the underlying data, carefully scoped so that the lock is held for the duration of the reference:
use std::sync::Mutex;
use std::collections::BTreeMap;
pub struct A {
synced_map: Mutex<BTreeMap<String, String>>,
}
impl A {
pub fn new() -> A {
A {
synced_map: Mutex::new(BTreeMap::new()),
}
}
}
impl A {
fn synchronized_call(&self) {
let mut map = self.synced_map.lock().unwrap();
// omitting the lambda for brevity, but it would also work
// (as long as it refers to map rather than self.map)
map.insert("hello".to_owned(), "d".to_owned());
}
}

Resources