Rust 如何创建一个智能指针,指向一个带有嵌入片的未调整大小的类型?

Rust 如何创建一个智能指针,指向一个带有嵌入片的未调整大小的类型?,rust,smart-pointers,Rust,Smart Pointers,我试图通过使用类似C的灵活数组成员来避免多个堆分配。为此,我需要分配一个无大小的结构,但我没有找到任何方法通过智能指针来实现。我特别感兴趣的是Rc,但是Box也是这样,所以我将在示例中使用这一点 以下是我迄今为止得到的最接近的结果: 使用std::alloc:{self,Layout}; 结构内部{/*大小字段*/} #[repr(C)]//确保数组始终是最后一个 //需要同时分配'inner'和'arr',但最好不要分开分配 无大小的结构{ 内:内, arr:[使用], } 公开的发布结构(框

我试图通过使用类似C的灵活数组成员来避免多个堆分配。为此,我需要分配一个无大小的结构,但我没有找到任何方法通过智能指针来实现。我特别感兴趣的是
Rc
,但是
Box
也是这样,所以我将在示例中使用这一点

以下是我迄今为止得到的最接近的结果:

使用std::alloc:{self,Layout};
结构内部{/*大小字段*/}
#[repr(C)]//确保数组始终是最后一个
//需要同时分配'inner'和'arr',但最好不要分开分配
无大小的结构{
内:内,
arr:[使用],
}
公开的发布结构(框);
impl暴露{
新发布(容量:usize)->Self{
//创建后跟数组的“内部”布局
let(布局,阵列基)=布局::阵列::(容量)
然后(| arr|u布局|布局::新::()。扩展(arr|u布局))
.unwrap();
设ptr=unsafe{alloc::alloc(layout)};
//此时,“ptr”是“*mut u8”,编译器不知道分配的大小
如果ptr.is_null(){
恐慌!(“内部分配错误”);
}
不安全{
演员阵容::()
.write(内部{/*初始化大小的字段*/});
让tmp_ptr=ptr.add(arr_base).cast::();
//初始化数组元素,在本例中为0
(0..容量)。对于每个(i | tmp | ptr.add(i).write(0));
//此时,所有内容都已初始化,可以安全地转换为“Box”`
Self(框::from_raw(ptr as*mut_u))
}
}
}
这不会编译:

error[E0607]:无法将细指针“*mut u8”强制转换为胖指针“*mut Unsized”`
-->src/lib.rs:32:28
|
32 | Self(框::from_raw(ptr as*mut|))
|                            ^^^^^^^^^^^^^
我可以直接使用
*mut u8
,但这似乎非常容易出错,需要手动删除


有没有办法从
ptr
创建胖指针,因为我实际上知道分配大小,或者从复合的非大小类型创建智能指针?

问题是指针
*mut unsized
是一个宽指针,所以不仅仅是一个地址,而是一个地址和片中元素的数量。另一方面,指针
*mut u8
不包含有关切片长度的信息。标准库提供了

  • std::ptr::从原始零件切片
  • std::ptr::从原始零件中切片
在这种情况下。因此,您首先创建一个假的(和错误的)
*mut usize

ptr as *mut usize
这就允许

slice_from_raw_parts_mut(ptr as *mut usize, capacity)
在宽指针中使用正确的长度字段创建一个假的(但仍然是错误的)
*mut[usize]
,然后我们将其随意转换

slice_from_raw_parts_mut(ptr as *mut usize, capacity) as *mut Unsized
它只改变类型(值不变),所以我们得到了正确的指针,现在我们终于可以将它输入到
Box::from_raw

演示此帖子的完整示例:

使用std::alloc:{self,Layout};
结构内部{/*大小字段*/}
#[repr(C)]//确保数组始终是最后一个
//需要同时分配'inner'和'arr',但最好不要分开分配
无大小的结构{
内:内,
arr:[使用],
}
公开的发布结构(框);
impl暴露{
新发布(容量:usize)->Self{
//创建后跟数组的“内部”布局
let(布局,阵列基)=布局::阵列::(容量)
然后(| arr|u布局|布局::新::()。扩展(arr|u布局))
.unwrap();
设ptr=unsafe{alloc::alloc(layout)};
//此时,“ptr”是“*mut u8”,编译器不知道分配的大小
如果ptr.is_null(){
恐慌!(“内部分配错误”);
}
不安全{
演员阵容::()
.write(内部{/*初始化大小的字段*/});
让tmp_ptr=ptr.add(arr_base).cast::();
//初始化数组元素,在本例中为0
(0..容量)。对于每个(i | tmp | ptr.add(i).write(0));
}
//此时,所有内容都已初始化,可以安全地转换为“Box”`
不安全{
Self(框::from_raw(
std::ptr::从原始零件(ptr为*mut usize,容量)切片为*mut Unsized,
))
}
}
}



旁注:您不需要
#[repr(C)]
来确保非大小切片字段位于末尾,这是有保证的。你需要的是知道字段的偏移量。

是否被限制为两个字宽?如果没有,您可以定义公开的发布结构(内部,框)
。您仍然只有一个分配,并且不需要不安全的。相关的开放RFC:@user4815162342抱歉,我不想提及
内部
也需要分配。我将对问题进行编辑,将其包括在内。另外,
暴露的
最好不要太大;谢谢,看起来方向正确。但是,此方法是否仅创建指向
Unsized
arr
成员大小的胖指针?(我想我可以从这里弄明白,只是想澄清一下)@chuck你所说的“仅限于
arr
成员的大小”是什么意思?我可能是错的,但我认为这只适用于
mem::size_of::()==0
(我可能不应该在示例中这样做)。然而,如果不是这样的话,我想
std::ptr::slice_from_raw_parts(ptr,capacity*mem::size_of::+mem::size_of::())作为*mut Unsized
可以使用,所以答案仍然解决了问题。@chuck我将
internal
更改为
struct internal(bool)
,它继续工作(并通过了Miri).那我就糊涂了-切片的大小不应该是吗