Confused by std::mem::drop


#1

It’s here:
http://doc.rust-lang.org/std/mem/fn.drop.html

Description goes like this:

Disposes of a value.

This function can be used to destroy any value
by allowing drop to take ownership of its argument.

Sounds powerful :slight_smile: Now, my understanding was I could do something like this:

use std::mem;
let x = 3; //any value

mem::drop(x); //take ownership

But as it turns out, x is still alive:

println!("{}", x);

But looking at the source, it’s only an empty function.
So, it would work for vector, for example, but doesn’t work for primitive/copy types.
The description implies some kind of magic is happening behind the scene.
Isn’t the description a bit misleading? Or something is yet to be implemented?


#2

Your 3 isn’t on the heap. It’s just a value on the stack – drop(_) only works on the heap. Also it implements Copy and its type is thus not affine.


#3

This works exactly as documented for Copy types, which have copy instead of move semantics:

http://doc.rust-lang.org/std/marker/trait.Copy.html

(Basically the first examples are equivalent to yours, minus the explicit drop)


#4

Wait, what? It works for any value. What it does is that it moves the value into the drop function and thus shortens its lifetime to that point. This works just as expected:

#[derive(Debug)]
struct A;

fn main() -> () {
    let a = A;
    std::mem::drop(a);
    println!("{:?}", a);
}

This is the reason why the 3 is still available. Things that implements Copy will not be moved, so drop has no effect.


#5

Sorry, I was being unclear. drop() works on any value, of course. However, it won’t – as the docs say – dispose of the value for Copy types, due to the fact that it will just receive a copy of the value (if it is used again).


#6

To be clear, this is litterally the implementation:

fn drop<T>(_junk: T) { }

It’s just an empty function that takes an argument by-value. Things that don’t normally get consumed when passed to a function will not be treated specially.


#7

Okay. But - how exactly then it can be used to destroy any value?

It can’t, because depending on the type it might act on a copy of a value.

Maybe it’s just me, but the description (in the docs)
was completely incomprehensible.


#8

You’re totally right, the docs should be improved. If you find a problem with a docs, please file an issue! :smiley:


#9

#10

Types that implements Copy are usually small “plain old data” types, like numbers and such (see the documentation). There are generally no real reason to drop these manually, with exception for maybe an Option with a number. You can always get a different behaviour by wrapping the type in a custom struct (e.g. struct MyIdType(usize);) and implement the functionality you want it to have. You can also use scopes to achieve a similar effect to what drop does, but that can be more limiting.


#11

More precisely, Copy and Drop are mutually exclusive, so values that are implicitly copied cannot have destructors, so there is nothing to dispose of. (Other than any stack memory that may be used for the value itself, but that’s a different can of worms, and if a type is large enough that overflowing the stack is a concern, it probably shouldn’t be on the stack to begin with.)


#12

Still making my first steps in Rust, so this is all valuable information.

The problem here is, if I want to reason correctly then it’s not enough
to read the book or std library docs.

I’m talking about specific way of thinking which maybe is second nature to
somebody who knows Rust. For example, this:

values that are implicitly copied cannot have destructors, so there is nothing to dispose of.

( I guess english term for this is convoluted way of thinking ) :slight_smile: To me, this sounds completely backwards.

I mean, values that are implicitly copied - values of types which implement Copy -
are still values. They are stored somewhere in memory.
There is something to dispose of.
Another thing is how useful it might be in practice.

And when you say destructor, I suppose you mean std::ops::Drop , not std::mem::drop ?


#13

Yes.

Sure, but they are not droped. They reach their end of life and are freed.


#14

std::mem::drop is for when you really need to get rid of the value at that precise moment. The exact same thing will otherwise happen at the end of the scope, so it will still be removed. Types that implements Copy should not carry any data that needs to be released in a special way, because they can’t implement a destructor (Drop). This prevents them from, for example, automatically freeing allocated memory or closing open files. There is therefore usually no reason to worry about when they are released. One exception would probably be if the memory limits are really tight.