This answer asserts that an equivalent of C++ shared_ptr
in rust is std::rc::Rc
. This is true on the surface but there is an important operation missing: Specifically, shared_ptr
can be used to point to an unrelated, unmanaged pointer, via its aliasing constructor (8), which is mostly used to point to a subpart of the original allocation. The shared_ptr
still keeps the object alive, but the original type is completely erased. This can be very useful to forget generic parameters (and other tricks).
Obviously, in Rust, managing a completely unrelated pointer would be incredibly unsafe. Yet there is precedence of such an operation: Ref::map allows one to obtain a Ref to a component of the original Ref, while "forgetting" the type of the former.
Implementation-wise, it is clear that the current Rc<T>
can not possibly implement this behaviour. When the refcount hits 0, it has to deallocate after all, and the layout must be exactly the same as when it allocated, thus it must use the same T
. But that's just because it doesn't store the Layout
that was originally used for the allocation.
So my question: Is there a library or other overlooked type that supports the allocation management of Rc
, while also allowing the equivalent of Ref::map
? I should mention that the type should also support unsize coercion.
struct Foo<T> {
zet: T,
bar: u16,
}
let foo: MagicRc<Foo<usize>> = MagicRc::new(Foo { zet: 6969, bar: 42 });
// Now I want to erase the generic parameter. Imagine a queue of
// these MagicRc<u16> that point to the `bar` field of different
// Foo<T> for arbitrary T. It is very important that Foo<..> does
// not appear in this type.
let foobar: MagicRc<u16> = MagicRc::map(&foo, |f| &f.bar);
// I can drop foo, but foobar should still be kept alive
drop(foo);
assert_eq!(*foobar, 42);
// unsizing to a trait object should work
let foodbg: MagicRc<dyn Debug> = foobar;
Addressing comments:
OwningRef
and the playground link (DerefFn
) do not erase the owner type.- Addressing Cerberus concern, such a type would store the
Layout
(a perfectly normal type) of the original allocation somewhere as part of the managed object and use it to free the value without having to have access to the original Type of the allocation.