Which I find fitting, since in Rust, the Box is (at least to me) more about indirection. The single-owner semantics just come in because Box follows the same rules as anything else, while for unique_ptr they are part of the pointer concept.
It uses Box to demonstrate ownership in the first section, but that works the same way with any Rust type unless said type was opted into copy semantics, there's nothing special or magical about Box (at least in that respect), it's just a wrapper for a raw pointer.
Unfortunately, it can be hard to have an example that's simple enough to understand, while still emphasising the right concepts. Hopefully we can find something.
As far as I know, the compiler should not copy in that instance. Rather, it should move.
> There is not one unit of memory that is "taken over," or if there was, then Rust would have a serious problem.
Could you elaborate on that? Rust does have an ownership model, and ownership can be transferred as in the example. What sort of problems would you expect that to cause? If you're worried that it will invalidate existing pointers, the compiler checks that for you. Unless you deliberately circumvent the check, the compiler guarantees that your pointers are valid.
Are you speaking about Rust specifically, or move in general? I had always understood that move was no more expensive than passing by reference. That is, I had thought the memory was on the heap and didn't need to be copied each time someone new took ownership of that heap space.
> That is, I had thought the memory was on the heap
An example:
let x = Box::new(5);
let y = x;
While the 5 is allocated on the heap, when we move x to y, _the pointer itself_ is memcpy'd. That's why Box<T> isn't Copy; as you say, a simple memcpy won't actually duplicate the structure. Make sense?(and in this case, I'd assume llvm's optimizations would realize the copy is superflous and just elide it, but semantically, that's what's up)
let x = BigExpensiveStruct::new();
some_function(x);
That won't trigger a big, expensive memcpy of the BigExpensiveStruct, will it? I'd thought that its memory was on the heap. struct Expensive {
cheap_value: u32,
expensive_value: Vec<u32>
}
Does that seem like a good maxim?Your intuition about the performance of this sort of thing might be served by reading about how calling conventions work. You might not need to copy the struct from a local variable to where it belongs on the stack or in registers when calling a function, either because the calling convention says you put a pointer to the struct somewhere (depending on its size) or because you're (you being a compiler) clever enough to put it in the place that'll end up in the argument list later. The callee, however, has less flexibility, and if it needs to pass the value somewhere else, it'll probably have to copy the data. This is way better than allocating it on the heap -- stuff on the stack is in the L1 cache, you compute it's location statically instead of having to traverse data structures, but yeah if you found yourself copying around a 1000-byte struct you might want to box it or pass it by reference. I only know about C and C++ calling conventions though, so don't infer from my comment that Rust isn't doing anything "special" for big non-copyable structs -- I wouldn't know.
If the value isn't passed by (perhaps elidably) copying, that would mean it's getting allocated on the heap and deallocated.
But I could be mistaken. This is all based on hearsay--just stuff I've read about the Rust compiler. I don't actually work on the compiler myself.