有没有办法防止Weak :: new()过度分配?

Mat*_* M. 10 rust

当Rc :: downgrade()做什么时,为什么Weak :: new()工作的后续工作呢?

当试图以Weak::new()一种不需要它为底层类型分配内存的方式实现时,即使它永远不会被使用,我遇到了障碍.

定义RcBox<T>很简单:

struct RcBox<T: ?Sized> {
    strong: Cell<usize>,
    weak: Cell<usize>,
    value: T,
}
Run Code Online (Sandbox Code Playgroud)

这里的目标是创建一个RcBox<T>实际上不包含任何内容的内容value.基本上,一个RcBox<()>.

然而,有一个障碍.*mut RcBox<()>是一个瘦指针,但*mut RcBox<T>可能是一个胖指针.我们有这个胖指针的数据部分,但有很多不同的胖指针的情况,所以试图合成其余的很难.

从链接的问题中可以看出,我可以使它适用于特征对象:

impl<T: ?Sized> Weak<T> {
    pub fn new() -> Weak<T> {
        unsafe {
            let boxed = Box::into_raw(box RcBox {
                strong: Cell::new(0),
                weak: Cell::new(1),
                value: (),
            });

            let ptr = if size_of::<*mut ()>() == size_of::<*mut T>() {
                let ptr: *mut RcBox<T> = transmute_copy(&boxed);
                ptr
            } else {
                let ptr: *mut RcBox<T> = transmute_copy(&TraitObject {
                    data: boxed as *mut (),
                    vtable: null_mut(),
                });
                ptr
            };

            Weak { ptr: Shared::new(ptr) }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

但是这不适用于str(例如).

我尝试隔离固定大小的部分,RcBox同时让编译器推断指针的胖部分:

struct RcBox<T: ?Sized> {
    counters: RcBoxCounters<T>,
    value: T,
}

struct RcBoxCounters<T: ?Sized> {
    strong: Cell<usize>,
    weak: Cell<usize>,
    _phantom: PhantomData<T>,
}

impl<T: ?Sized> Weak<T> {
    pub fn new() -> Weak<T> {
        unsafe {
            let boxed = Box::into_raw(box RcBox::Counters::new(0, 1));
            Weak { ptr: Shared::new(boxed as *mut RcBox<T>) }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这听起来非常聪明,直到编译器压缩你的热情:

error[E0375]: implementing the trait `CoerceUnsized` requires multiple coercions
  --> <anon>:58:40
   |
58 | impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<RcBox<U>> for RcBox<T> {}
   |                                        ^^^^^^^^^^^^^^^^^^^^^^^ requires multiple coercions
   |
   = note: `CoerceUnsized` may only be implemented for a coercion between structures with one field being coerced
   = note: currently, 2 fields need coercions: counters (RcBoxCounters<T> to RcBoxCounters<U>), value (T to U)
Run Code Online (Sandbox Code Playgroud)

那是:

  • 我认为,让编译器合成脂肪的一部分,我需要一个PhantomDataRcBoxCounters,
  • 但这样做需要2次强制转换,这是不允许的.

那么,有没有办法解决Weak::new()它停止分配无关(不必要的)内存?

注意:我的意思是只为两个计数器分配空间,分配大和后续修剪无济于事.

注意:有人指出,人们可以使用Option或特殊值来表示缺乏价值.这需要在每种方法上进行分支,这可能是不可取的.我更喜欢学会摆弄胖指针.

She*_*ter 3

是的,有办法,而且居然提交到了标准库:

此更改使得 Weak::new() 根本不分配内存。相反,它是用空指针创建的。Weak 所做的唯一事情就是尝试升级、克隆和删除,这意味着代码实际上需要检查指针是否为空的地方很少。