我处于处理包装在Arc
中的数据的情况,有时我最终会使用Arc
来获取指向基础数据的原始指针。我的用例还要求类型擦除,因此原始指针通常被强制转换为into_raw
,然后在重新构建into_raw
时又强制转换为适当的具体类型。
我遇到了这样一种情况,即能够克隆*const c_void
而无需了解基础数据的具体类型会很有用。据我了解,仅出于调用Arc
的目的而使用伪类型重建Arc
应该是安全的,只要我从未实际取消引用数据即可。因此,例如,这应该是安全的:
Arc
我遗漏了什么东西,使它实际上不安全?另外,我认为答案也适用于clone
,但是如果有任何差异,请告诉我!
实际上,这“可能”是安全的,但您对此不做任何保证,也没有可移植性:
pub unsafe fn clone_raw(handle: *const c_void) -> *const c_void {
let original = Arc::from_raw(handle);
let copy = original.clone();
mem::forget(original);
Arc::into_raw(copy)
}
只是指向大致看起来像堆分配的结构的指针
Rc
Arc<T>
给您指向struct ArcInner<T> {
strong: atomic::AtomicUsize,
weak: atomic::AtomicUsize,
data: T,
}
元素的指针。 into_raw()
的实现采用这样的指针,assumes是指向data
中Arc::from_raw()
元素的指针,在内存中返回并在assumes中找到一个data
。此假设取决于ArcInner<T>
的内存布局,尤其是对齐方式。如果您在ArcInner<T>
上调用T
,然后像在into_raw
和ArcInner<U>
对齐方式不同的from_raw
一样调用ArcInner<V>
,则对U
/ V
的位置进行偏移计算放在U
中将是错误的,整个事情都会崩溃。
实际上,这很可能不会出现问题:由于V
是两个ArcInner
元素之后的第三个元素,因此任何data
都可能以相同的方式对齐。但是,如果更改了stdlib的实现,则重建由usize
和T
的内存布局不同的Arc<V>::from_raw
创建的Arc<U>
将是不安全的,并且会崩溃。