Generics 不安全队列实现
我试图创建一个不安全但性能更高的Generics 不安全队列实现,generics,rust,segmentation-fault,queue,unsafe,Generics,Rust,Segmentation Fault,Queue,Unsafe,我试图创建一个不安全但性能更高的ArrayQueue实现。在我添加测试用例之后,其中一个生成了一个分段错误。 下面是我的简单的最小实现: use std::mem; pub struct ArrayQueue<T> { buff: Vec<T>, head: usize, size: usize, } impl<T> ArrayQueue<T> { pub fn new(size: usize) -> Se
ArrayQueue
实现。在我添加测试用例之后,其中一个生成了一个分段错误。
下面是我的简单的最小实现:
use std::mem;
pub struct ArrayQueue<T> {
buff: Vec<T>,
head: usize,
size: usize,
}
impl<T> ArrayQueue<T> {
pub fn new(size: usize) -> Self {
let mut buff = Vec::with_capacity(size);
unsafe {
buff.set_len(size);
}
ArrayQueue {
buff: buff,
head: 0,
size: 0,
}
}
pub fn add(&mut self, elem: T) {
let idx = (self.head + self.size) % self.buff.len();
*unsafe { self.buff.get_unchecked_mut(idx) } = elem;
self.size += 1;
}
pub fn remove(&mut self) -> T {
let idx = self.head;
self.size -= 1;
self.head = (self.head + 1) % self.buff.len();
mem::replace(unsafe { self.buff.get_unchecked_mut(idx) }, unsafe {
mem::uninitialized()
})
}
}
impl<T> Drop for ArrayQueue<T> {
fn drop(&mut self) {
let mut idx = self.head;
for _ in 0..self.size {
// Drop only valid elements of the queue
drop(unsafe { self.buff.get_unchecked_mut(idx) });
idx = (idx + 1) % self.buff.len();
}
unsafe {
// Prevent deallocation of vector elements
// This still dallocates vector's internal buffer
self.buff.set_len(0);
}
}
}
#[cfg(test)]
mod test {
use super::ArrayQueue;
#[test]
fn test0() {
let mut x = ArrayQueue::new(10);
x.add(String::from("K"));
assert_eq!(x.remove(), String::from("K"));
}
#[test]
fn test1() {
let mut x: ArrayQueue<Box<String>> = ArrayQueue::new(10);
x.add(Box::new(String::from("K")));
assert_eq!(x.remove(), Box::new(String::from("K")));
}
}
使用std::mem;
发布结构数组队列{
buff:Vec,
负责人:usize,
大小:usize,
}
impl阵列队列{
pub fn new(尺寸:usize)->Self{
让mut buff=Vec::具有_容量(大小);
不安全{
buff.set_len(大小);
}
阵列队列{
牛:牛,
总人数:0,
尺寸:0,
}
}
发布fn添加(&mut self,元素:T){
设idx=(self.head+self.size)%self.buff.len();
*不安全{self.buff.get_unchecked_mut(idx)}=elem;
自身大小+=1;
}
发布fn删除(&mut self)->T{
设idx=self.head;
自我尺寸-=1;
self.head=(self.head+1)%self.buff.len();
mem::replace(不安全{self.buff.get_unchecked_mut(idx)},不安全{
mem::uninitialized()
})
}
}
ArrayQueue的impl Drop{
fn下降(&mut自我){
让mut idx=self.head;
对于0..self.size中的uu{
//仅删除队列的有效元素
drop(不安全{self.buff.get_unchecked_mut(idx)});
idx=(idx+1)%self.buff.len();
}
不安全{
//防止向量元素的释放
//这仍然是向量的内部缓冲区
自抛光设置(0);
}
}
}
#[cfg(测试)]
模试验{
使用super::ArrayQueue;
#[测试]
fn test0(){
让mut x=ArrayQueue::new(10);
x、 添加(字符串::from(“K”);
assert_eq!(x.remove(),String::from(“K”);
}
#[测试]
fn test1(){
让mut x:ArrayQueue=ArrayQueue::new(10);
x、 添加(Box::new(String::from(“K”));
assert_eq!(x.remove(),Box::new(String::from(“K”));
}
}
我相信我正在进行适当的删除,以防止任何内存泄漏
我附加了两个测试用例,其中一个可以工作,但另一个由于无效的内存引用而导致崩溃
它在add
方法(*不安全{self.buff.get_unchecked_mut(idx)}=elem;
)中崩溃,我怀疑发生这种情况是因为我试图写入无效的内存位置。我在测试中专门为向量元素使用了堆分配的对象,但令我惊讶的是,
String
工作正常,而Box
工作不正常
我想了解是否有可能实现这样一个不安全的实现,以及为什么它目前失败了
编辑
我通过替换
*unsafe{self.buff.get_unchecked_mut(idx)}=elem解决了这个问题代码>使用不安全的{std::ptr::write(self.buff.get_unchecked_mut(idx),elem)}代码>
现在我想理解为什么当您运行*unsafe{self.buff.get_unchecked_mut(idx)}=elem时,此功能可以正常工作,而以前的版本不能运行
要替换未初始化的框
或字符串
,它将在此未初始化的框
或字符串
上运行drop
Box
和String
都包含一个指针,指向堆中应该存储其数据的部分,当它们被丢弃时,它将在此位置释放内存
通过删除未初始化的框
或字符串
,它将在任意位置释放内存,因为未初始化的指针可以是任何东西。取消分配尚未分配的内存是未定义的行为。当您运行*unsafe{self.buff.get\u unchecked\u mut(idx)}=elem
要替换未初始化的框
或字符串
,它将在此未初始化的框
或字符串
上运行drop
Box
和String
都包含一个指针,指向堆中应该存储其数据的部分,当它们被丢弃时,它将在此位置释放内存
通过删除未初始化的框
或字符串
,它将在任意位置释放内存,因为未初始化的指针可以是任何东西。释放尚未分配的内存是未定义的行为。我认为这是or的重复。TL;DR-您正在删除尚未初始化的值。您正在将长度设置为一个数字,但该范围内的值是未初始化内存。不,我认为在未初始化内存上调用drop没有任何问题。就我所见,add
方法在为未初始化的内存赋值时出现了问题,这就是这个不安全代码的问题所在。将新值分配给索引时,正在删除元素。如果您使用(size,T::default)buff.resize_
而不是set\u len
它将不再崩溃,这纯粹是运气。如上所述,您正在访问未初始化的内存,这是一种未定义的行为。不要这样做;)可以使用mem::forget
不调用要交换的元素的析构函数。总之,不要这样做。初始化是一次性的,这不是代价高昂的事情。你正在徒劳地破坏生锈的安全目的。这不会发生在字符串中,因为这是未定义的行为。你无法预测会发生什么或何时发生。它可能会在不同的操作系统、不同的CPU体系结构或未来的Rust编译器中崩溃。我认为这是或的复制品。TL;DR-您正在删除尚未初始化的值。您正在将长度设置为一个数字,但该范围内的值是未初始化内存。不,我认为在未初始化内存上调用drop没有任何问题。就我所见,add
方法在为未初始化的内存赋值时出现了问题,而这正是pr