When I pass the ownership of a large noncopy struct what exactly happens?

I am trying to understand how are the values exactly passed around. When I pass a large struct to a function does it pass a mutable reference behind the schenes or actually creates a new struct identical to the one I just passed in ?

Conceptually, it creates a new struct identical to the one you passed in (a shallow copy, if it contains things like Box or Vec).

I say "conceptually" because there are two answers to this question: the behavior of the language, and the behavior of a particular set of compiler optimizations. In practice, if you compile without --release, you will get code that literally copies the entire struct to a new location. With optimizations enabled, however, it depends on context.

I have never seen rustc optimize the passing of a large argument struct by passing a reference. It's not clear to me that this optimization is possible (as the callee would need to own the space for the struct). Returning a struct can often be done without copying, as the caller passes in a pointer to some uninitialized memory where the struct should be deposited.

However, if the function you're calling gets inlined by the compiler, this stops mattering, and the "passing" of the struct usually disappears completely. rustc is pretty aggressive about inlining.

If you're asking this question because of performance concerns, if you can pass a struct by reference or owned pointer (such as Box), and the struct is bigger than a few pointers in size, it will generally be faster than passing it by value, and this will be true whether or not the optimization gods smile on you today.

2 Likes

Clippy also has a helpful lint for finding where pass-by-value is likely to be faster. Their heuristic is 'if the value is Copy and is smaller than two general purpose registers'.

2 Likes