Question regarding Copy and drop glue

Hi all,

I have a question of understanding regarding drop glue and types which are Copy.

As far as I know types which are Copy don't get any drop glue from the compiler. Then how are they cleaned up?

Are they perhaps otherwise implicitly cleaned up by the stack? I've currently no idea.

Regards
keks

I'm not really sure what you mean by "cleaned up". Memory on the stack will just be reused. The next time that memory location is used as part of a stack value, the old memory will simply be overwritten with a new value.

Copy types definitionally don't need additional logic to clean up after them, since they can't implement Drop and can't contain other types that aren't Copy.

4 Likes

I'm sorry, I'm trying to make my statement more precise:

As I understand it, the compiler inserts drop glue in the program for certain types in order to make the used memory available again for other purposes but I've read (eg here) that the compiler won't add any drop glue for types which are Copy. So my question is: Which mechanism(s) ensures that the used memory of such types, which are Copy, gets freed again?

The drop glue is responsible for calling the Drop impls to free resources held by the value. The memory containing the value itself is not freed up by the drop glue. As a Copy type can't have any associated resources by the virtue of not being able to implement Drop and by being freely copyable, there is no drop glue to run. If the value is held on the stack, the memory is reused either when the function returns or in some cases if the value becomes dead and the compiler reused the place on the stack for another value. If the value is on the heap, the drop glue of the value owning the heap location (eg Box or Vec) is responsible for freeing the memory, not the value that is stored on the heap itself.

4 Likes

The compiler will always make the memory free for other purposes, regardless of whether the type is Copy or not. Some types need to do more than just have their memory freed when they go out of scope - for this purpose, Rust has the Drop::drop trait method, which you implement to have the compiler run code when your type goes out of scope, just before the compiler inserts code that frees the memory for your instance.

"Drop glue" is the code the compiler inserts to run Drop::drop methods when you let a value go out of scope. This allows for (e.g.) a std::fs::File to close the file it has open just before you free up the memory that tells the std::fs::File code which file you have open.

1 Like

@bjorn3 and @farnz

For my understanding what you say about drop glue is not correct according to std::ops::Drop

My current understanding about drop glue is that the compiler might even add drop glue for a type that is not Drop.

Well, a simple example is that String does not implement Drop itself, but it definitely has drop glue for its Vec field. But a type can only implement Copy if all of its fields do as well, so there can't be any drop glue at all.

4 Likes

Drop glue exists to call drop on the fields of a type if the field types implement Drop.

If none of the fields implement Drop, there's no need for drop glue code to be generated.

7 Likes

Omg... I completely misunderstood something while reading std::ops::Drop... sorry folks! :smiley: Thank you very much for your help!!!

Of course, to be more precise, fields that don't implement Drop but merely have Drop glue are also causing their parent type to have Drop glue. I. e. it's a recursively defined thing, considering fields, and fields of fields, and fields of fields of fields, and so on.

(Also as a special case, types like MaybeUninit or ManuallyDrop never have drop glue.)

4 Likes

MaybeUninit is a union, so isn't exactly a special case -- the rule is

unions cannot contain fields that may need dropping

note: a type is guaranteed not to need dropping when it implements Copy, or when it is the special ManuallyDrop<_> type

And thus MaybeUninit is taking advantage of ManuallyDrop's special case to work, rather than being special itself:

2 Likes

Alright. In my mind I would have considered that an implementation detail :innocent:

1 Like

It's never clear to me what should or shouldn't be considered that.

After all, rustdoc thinks it's important that it's a union https://doc.rust-lang.org/nightly/std/mem/index.html#unions

So I go with "you could write your own MaybeUninit, but you can't write your own ManuallyDrop".

3 Likes

Of course, I fully agree with this. On the other hand, I think it's also useful that one can understand MaybeUninit without considering (or even knowing) that it's implemented using a union.

Regarding the documentation distinguishing struct from union, AFAIR that's a point that has existing discussions as to whether that's something rustdoc should maybe not call out for opaque types.

1 Like

I get it, abstraction boundary and all, but I need to look behind the curtain often enough I get annoyed when rustdoc omits information... much less intentionally obscures it.

1 Like