I was trying to understand how structs behave when returned from methods. There is a section in the nightlies section of the "Rust Book" that said if you used the syntax...
let x = box i_return_a_struct();
.. that there wouldn't be a copy, therefore there is no need to return a pointer. But when I started playing with it, it appears that the box
is not needed, unless you need the value to exist on the heap.
#[derive(Debug)]
struct Dummy {
data: i64,
}
impl Drop for Dummy {
fn drop(&mut self) {
println!("{:?} is going out of scope", self as *const Dummy);
}
}
fn make_dummy(i: i64) -> Dummy {
Dummy { data: i }
}
fn main() {
{
let i = 15i32;
println!("{:?} is a variable on the stack frame", &i as *const i32);
let dummy1 = make_dummy(1);
println!("{:?} was returned and is being used", &dummy1 as *const Dummy);
let dummy2 = make_dummy(2);
println!("{:?} was returned and is being used", &dummy2 as *const Dummy);
let dummy3 = Box::new(make_dummy(3));
println!("{:?} box was returned and is being used", &(*dummy3) as *const Dummy);
let dummy4 = Box::new(make_dummy(4));
println!("{:?} box was returned and is being used", &(*dummy4) as *const Dummy);
}
println!("Leaving main");
}
Output:
0x23fb94 is a variable on the stack frame
0x23faf8 was returned and is being used
0x23fa50 was returned and is being used
0x2825030 box was returned and is being used
0x2825040 box was returned and is being used
0x2825040 is going out of scope
0x2825030 is going out of scope
0x23fa50 is going out of scope
0x23faf8 is going out of scope
Leaving main
Do values/structs in return position always get allocated in the parents stack frame or receiving box?
EDIT: PS - is there any guidance in the docs for as to when copy elision will occur in general?
EDIT: Beyond the accepted solution, the following Q+A was enlightening: What are move semantics exactly? Clarified many points for me.
Maybe it's not clear to me what you don't understand. I think you understand, but maybe you don't know yet :D
Normally, the return value of a function (make_dummy
for example) is pushed on the stack. Now suppose you want the object on the heap instead. With the new box syntax the compiler can do some optimization if you want the object on the heap.
Now let's take the example from the book.
let y: Box<Dummy> = box make_dummy(some_dummy);
You may think that in the above example the following happens:
make_dummy
is written into the stack (as normally)Dummy
objectDummy
value on the stack is copied in the memory pointer by the box object.With the old Box::new
mechanism this is exactly what would happen.
Instead, thanks to the experimental box syntax, this happened:
make_dummy
function (with some compiler magic), so the return value is written directly to the boxed memory [there's no extra copies involving the stack]I hope it's more clear now.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With