Does the variable s
in print_struct
refer to data on the heap or on the stack?
struct Structure {
x: f64,
y: u32,
/* Use a box, so that Structure isn't copy */
z: Box<char>,
}
fn main() {
let my_struct_boxed = Box::new(Structure {
x: 2.0,
y: 325,
z: Box::new('b'),
});
let my_struct_unboxed = *my_struct_boxed;
print_struct(my_struct_unboxed);
}
fn print_struct(s: Structure) {
println!("{} {} {}", s.x, s.y, s.z);
}
As I understand it, let my_struct_unboxed = *my_struct_boxed;
transfers the ownership away from the box, to my_struct_unboxed
, and then to s
in the function print_struct
.
What happens with the actual data? Initially it is copied from the stack onto the heap by calling Box::new(...)
, but is the data some how moved or copied back to the stack at some point? If so, how? And when is drop
called? When s
goes out of scope?
The ownership of a variable follows the same pattern every time: assigning a value to another variable moves it. When a variable that includes data on the heap goes out of scope, the value will be cleaned up by drop unless ownership of the data has been moved to another variable.
When we talk about ownership in Rust, we generally mean – a variable owns a value. As we assign the same value between variables, we move the value, changing the owner. While this is true for Rust Owned types, the behavior is different for Rust References (also known as Borrowed types).
However, the general rule is that the transfer of ownership depends upon the intention of the parties to the contract. The parties may fix any time for the transfer of ownership from the seller to the buyer.
It is necessary to determine the time at which the ownership of the goods is transferred to the buyer. Secs. 18 to 24 of the Indian Sale of Goods Act 1930 deal with the rules for the transfer of ownership which determine the time at which the ownership of the goods is transferred from the seller to the buyer.
In case of sale of unascertained goods, the ownership is transferred to the buyer as and when the goods are identified and are set apart for the purpose of delivering to the buyer. The ownership in case of unascertained goods is transferred to the buyer only on the fulfillment of the following two conditions:
It uses the ownership model to decide where to free memory; when the owner goes out of scope, the memory is freed. What are the stack and the heap? The stack and heap are both memory storage segments that are available for your code to use at runtime.
The Structure
data in my_struct_boxed
exists on the heap and the Structure
data in my_struct_unboxed
exists on the stack.
Therefore naïvely speaking (no compiler optimizations), a move or copy operation when dereferencing (*
) your Box
will always involve copying of the data. On the borrow-checker/static-analysis side, since the Copy
trait is not implemented for Structure
, this represents a transfer of ownership of the data to the my_struct_unboxed
variable.
When you call print_struct
, another copy would take place that would copy the bits in memory representing your Structure
from the local variable to the function's arguments call-stack. Semantically, this again represents a transfer of ownership into the print_struct
function.
Finally when print_struct
goes out of scope, it drops the Structure
which it owns.
Reference: std::marker::Copy
Excerpt
It's important to note that in these two examples, the only difference is whether you are allowed to access [your variable] after the assignment. Under the hood, both a copy and a move can result in bits being copied in memory, although this is sometimes optimized away.
Note the last part "this is sometimes optimized away". This is why the earlier descriptions were simplified to assume no compiler optimizations i.e. naïve. In a lot of cases, the compiler will aggressively optimize and inline the code especially with higher values for the opt-level
flag.
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