Does a drop somehow say something to the type system as well, disallowing reads and writes afterwards? I'm new to rust, sorry if that's a stupid question.
Does a drop somehow say something to the type system as well, disallowing reads and writes afterwards? I'm new to rust, sorry if that's a stupid question.
https://github.com/rust-lang/rust/blob/master/src/libcore/me...
Yes.
pub fn drop<T>(_x: T) { }
I understand that the drop function is simply taking ownership of the passed value so Rust knows that once "drop" finishes, the _x can be 'dropped'.
But I though that the T had to be bound to have "Drop" trait (i.e. T: Drop) so that Rust knows it's possible to insert the call to 'drop' like _x.drop()?
The `drop` here is just a simple library function and isn't technically related to the `Drop` trait, which is implemented with magical compiler pixie dust and allows you to define a destructor via a `.drop` method. Anything that goes out of scope has this `.drop` method called automagically.
You're correct in that if you were calling `x.drop()` explicitly, you would need to have a `Drop` bound on `T`.
If dropping was really implemented that way, every type would need to implement the Drop trait. Because otherwise there would be no way to free any memory at all.
Instead, Rust knows how to free any object. Implementing Drop is optional, and you only need to do it if you want some custom behavior at destruction.
Is there a trade-off involved here?
To take this to the logical extreme, see this awesome post from Walter Bright, where he doubles the speed of the D compiler by providing a custom malloc implementation that never frees, leaking all memory until the end of the process: http://www.drdobbs.com/cpp/increasing-compiler-speed-by-over...
I think one middle-path could be to mark the resource as released as soon as compiler detects it, and then release it
1. when the allocator is starved or
2. when the resource goes out of scope
3. when drop() is explicitly called
I believe we have discussed your first bullet point there, with regard to attempting to free waiting-for-the-scope-to-end-but-not-being-used memory in the event that allocation fails. But this is a hairy subject, and is beyond my expertise.
Note that your third bullet point does cause memory to be freed immediately, because the `drop` function is a scope all its own.
{
let _lock = acquire_lock();
use_resource();
} // lock is released here, whether use_resource() returned or caused stack unwinding1. Give ownership away to something else.
2. Free the object at the end of the scope.
In order to do anything to the object, you give up ownership to the function that does it (which can then give it back, if it doesn't need ownership of the value any more and doesn't want to free it itself). This even applies to the `drop` function, which just takes ownership and then does nothing whatsoever to the passed-in value, allowing it to go out of scope immediately. So once you've called `drop(foo)`, you no longer own the value and so can't give it away to any reading or writing function, and you can't drop it for the very same reason.