Why does an explicit drop cause a move, but an implicit drop does not?

Just a strange little thing I noticed. Playground link.

We see that in the first block when Foo is dropped implicitly as it exits scope, it's address remains the same.
But when we drop Foo explicitly in the second block, it is moved to a new location before drop is called!

Why is this? It seems inefficient.

Because debug mode isn't particularly efficient. When I run the code in release mode, both behave the same. But other than that, I am confused as well.

1 Like

Because Foo is moved into the std::mem::drop function. Drop::drop is then implicitly called on it at the end of the mem::drop function as the variable exits the scope. Since mem::drop itself is empty it's basically guaranteed to be inlined with any optimization level, so this only happens in debug mode.

1 Like

Interesting. I came up with this small example to show the behavior I was seeing in something larger. In the larger program I tried it in both debug and release mode. Maybe it's going over the inlining quota?

(Could also be the large amounts of unsafe code...)

Try cargo test --release -- --nocapture on this:

Because the std::mem::drop function isn't special at all. Whenever you call a function with an argument by value, the argument is moved into the function. This is true for every function, including std::mem::drop.

std::mem::drop is just an empty helper function – you could write your own std::mem::drop if you want! (Perhaps the compiler favors inlining a function within the same crate more? Not sure, but if that is the case it might be worth seeing if writing your own mem::drop would encourage it to inline.).

I think std::mem::drop should perhaps be marked #[inline(always)], but it's currently just #[inline].


Sorry for the old post revival, I'm just posting for future reference: if you really want an inline drop, I think a macro should be more friendly to the compiler than a #[inline(always)] function:

macro_rules! drop { ($var:ident) => (
        { $var; }