Turn the last instance of an Arc<T> into a Box<T> instead of a T

I have an Arc<dyn MyTrait>, and MyTrait (which I define) needs to have a method that takes an owned self for cleanup after the Arc has served its purpose. Since trait objects are unsized, I cannot call into_inner() on the Arc directly. I would prefer to have this cleanup method take e.g. a Box<Self> rather than an Arc<Self> which the implementation then calls `into_inner() on. Is this possible?

1 Like

Box<T> and Arc<T> aren't layout compatible, so there's no way to convert from one to the other without allocate-move-deallocate.

You're not going to be able to do that on Box either, as it also requires T: Sized.

1 Like

You'll need some sort of downcasting. I can try to whip up an example later. It will look something similar to this.

The standard library supports Box to Arc conversion but not the other way around. It seems like adding TryFrom<Arc<T>> for Box<T> could be useful.

1 Like

Box and Arc aren't layout compatible

Does that mean just that the Box and Arc structs themselves have different layouts meaning I can't directly transmute() them (which is obvious) or that they treat the raw pointer to a T inside them in different, incompatible ways re: what data it points to / when to call free()? In theory, at least, I could check to make sure I really do have the last instance of an Arc, call Arc:: as_raw_ptr(), forget() the Arc, and then call Box::from_raw_ptr(). I'm not at all sure that what I just described is sound in terms of memory (de)allocation, but it should be sound in terms of layout (at least of the T).

You wouldn't be able to call into_inner() on the Box either, since it requires T: Sized.

Well of course not, but I could have my cleanup function take self: Box<Self>.

At least currently,[1] Arc<T> puts the counters and value in one allocation, so the allocation is not compatible with Box<T> (that just has the value).


  1. implementation detail to date AFAIU ↩︎

2 Likes

Why does Box there matter to you, instead of Arc?

Could the cleanup take &mut, say, and thus you use https://doc.rust-lang.org/std/sync/struct.Arc.html#method.get_mut instead?

And of course deallocating just the first 16 bytes of an N+16-byte allocation isn't really possible with Rust's allocation model.

Rats. Well, guess I could just pass an owned Arc<Self> and have the implementation call into_inner() now that it knows what type it is.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.