I have two structs, Holder
and Held
. Holder
holds a reference to Held
. Held
holds an i32
:
struct Holder<'a> {
val: &'a Held,
}
#[derive(Debug)]
struct Held(i32);
I want to create 10 Holder
s in a Vec<_>
named holders
. Since Holder
takes a reference to Held
struct, I also create a Vec<_>
named heldvals
that will store the Held
structs for the scope of main
function:
pub fn main() {
// contains the `Holder`s
let mut holders = vec![];
// contains the `Held`s
let mut heldvals = vec![];
for i in 0..10 {
heldvals.push(Held(i));
holders.push(Holder {
val: &heldvals.last().unwrap(),
});
}
}
When I attempt to compile this program, I get an error:
error[E0502]: cannot borrow `heldvals` as mutable because it is also borrowed as immutable
|
| heldvals.push(Held(i));
| ^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
|
| holders.push(Holder {
| ------- immutable borrow later used here
| val: &heldvals.last().unwrap(),
| -------- immutable borrow occurs here
As a workaround, I reluctantly decided to use unsafe
, which works without any errors. I even implemented the Drop
trait to confirm that there is no memory issue.
// ...
impl Drop for Held {
fn drop(&mut self) {
dbg!(self);
}
}
pub fn main() {
let mut holders = vec![];
let mut heldvals = vec![];
let hptr = &mut heldvals as *mut Vec<Held>;
for i in 0..10 {
println!("creation");
unsafe {
(*hptr).push(Held(i));
}
holders.push(Holder {
val: &heldvals.last().unwrap(),
});
println!("replacement");
}
}
Running the code above gives this (reduced) output:
creation
replacement (10 times)
[src/main.rs:12] self = Held(
0,
)
...
[src/main.rs:12] self = Held(
9,
)
Valgrind shows no memory leaks or issues either:
HEAP SUMMARY:
in use at exit: 0 bytes in 0 blocks
total heap usage: 18 allocs, 18 frees, 3,521 bytes allocated
All heap blocks were freed -- no leaks are possible
ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Is there a way to avoid the usage of unsafe
? I found out about Vec::reserve()
, is that a good idea?
Note that usage of reference counters is impossible for me. I want a simple way to hold references until program exits.