将共享引用&
转换为强Arc<T>
类型,然后再转换为Weak<T>
类型的共享引用,这样做是否安全?
换句话说:下面的函数sound吗?还是存在潜在漏洞?
pub fn as_weak<'a, T>(strong: &'a Arc<T>) -> &'a Weak<T> {
unsafe { transmute::<&'a Arc<T>, &'a Weak<T>>(strong) }
}
为什么我想这样做
我们有一个现有的函数,返回一个&Weak<T>
。内部数据结构有些变化,我现在有一个Arc<T>
,之前有一个Weak<T>
,但我需要保持与该函数接口的semver兼容性。如果不需要,我宁愿避免只为此函数存储一个实际的Weak<T>
副本。
为什么我希望这是安全的
Arc<T>
和Weak<T>
的底层内存表示相同:一个非空指针(或类似于指针的值Weak::new()
),指向一个内部的ArcInner
结构,其中包含强引用计数、弱引用计数和内部T
值。
Arc<T>
中还包含一个PhantomData<T>
,但我的理解是,如果有任何变化,它只会在释放时应用,这对于我们仅转换共享引用而不是拥有值的情况并不相关。
Arc<T>
将对其内部指针执行的操作可能是Weak<T>
可以执行的操作的超集,因为它们具有相同的表示,但Arc
提供了一个保证,即内部T
值仍然存在,而Weak
则没有。
考虑到这些事实,我认为不会出现任何问题。然而,我之前没有写过太多unsafe
代码,也从未像这样为生产案例编写过。我不确定我完全理解可能出现的问题。这种转换是否安全可靠,或者还需要考虑其他因素?
#[repr(transparent)]
以启用此功能。链接:https://internals.rust-lang.org/t/marking-arc-rc-weak-as-repr-transparent/17171?u=jeremybanks - user19567871Arc
/Rc
/Weak
类型标记为#[repr(transparent)]
,仍然不适合转换它们,因为只要字段是私有的,表示仍被视为私有。因此,这种转换只能由标准库本身安全地执行。让我们看看Rust团队对此的看法:Rust PR#100472:添加函数Arc/Rc :: as_weak(…)以将&Arc/Rc转换为&Weak。 - user19567871