gpt4 book ai didi

rust - `&mut retval`和 `retval as *const T as *mut T`有什么区别?

转载 作者:行者123 更新时间:2023-12-03 11:28:19 28 4
gpt4 key购买 nike

我很难理解以下代码为何具有2种不同的行为:

pub fn get(&self, idx: usize) -> &T {
let arr = unsafe { core::slice::from_raw_parts(self.elements, self.count) };
&arr[idx]
}

当我调用:
unsafe { ptr::drop_in_place(self.get(i) as *const T as *mut T) };

它可以正常工作,并且将值放到适当的位置,但是将强制类型转换为 &mut不会:
unsafe { ptr::drop_in_place(&mut self.get(i)) };

我期望编译器产生错误,因为 T不支持克隆/复制,但事实并非如此。有什么解释?

最小示例:
use core::*;

pub struct Vec<T> {
elements: *mut T,
count: usize,
capacity: usize,
}

pub fn alloc_array<T>(count: usize) -> *mut T {
let size = mem::size_of::<T>() * count;
let addr = unsafe { libc::memalign(mem::size_of::<usize>(), size) as *mut T };
unsafe { libc::memset(addr as *mut libc::c_void, 0, size) };
addr
}

pub fn free_array<T>(arr: *mut T) {
unsafe { libc::free(arr as *mut libc::c_void) };
}

impl<T> Vec<T> {
pub fn new() -> Self {
Self {
elements: ptr::null_mut(),
count: 0,
capacity: 0,
}
}

pub fn len(&self) -> usize {
self.count
}

pub fn pushBack(&mut self, t: T) {
if self.count >= self.capacity {
let newSize = if self.capacity == 0 {
16
} else {
self.capacity * 2
};
let old = self.elements;
self.elements = alloc_array(newSize);
self.capacity = newSize;

let oldArr = unsafe { core::slice::from_raw_parts_mut(old, self.count) };
let newArr = unsafe { core::slice::from_raw_parts_mut(self.elements, self.count + 1) };

for i in 0..self.count {
let v = unsafe { ptr::read(&oldArr[i] as *const _) };
newArr[i] = v;
}
}
let arr = unsafe { core::slice::from_raw_parts_mut(self.elements, self.count + 1) };

arr[self.count] = t;
self.count += 1
}

pub fn pop(&mut self) -> Option<T> {
if self.count == 0 {
None
} else {
self.count -= 1;
Some(unsafe { ptr::read(self.get(self.count) as *const _) })
}
}

#[inline]
pub fn get(&self, idx: usize) -> &T {
let arr = unsafe { core::slice::from_raw_parts(self.elements, self.count) };
&arr[idx]
}
}

impl<T> Drop for Vec<T> {
fn drop(&mut self) {
println!("Dropped");
for i in 0..self.count {
//unsafe { ptr::drop_in_place(self.get(i) as *const T as *mut T) }; // Works
unsafe { ptr::drop_in_place(&mut self.get(i)) }; // Doesn't Works
}
if self.capacity != 0 {
free_array(self.elements);
}
}
}

fn main() {
let mut v = Vec::<Vec<i32>>::new();
for i in 0..10 {
let mut vj = Vec::<i32>::new();
for j in 0..10 {
vj.pushBack(j);
}
v.pushBack(vj);
}
}

瓦尔格隆德:

Dropped
Dropped
Dropped
Dropped
Dropped
Dropped
Dropped
Dropped
Dropped
Dropped
Dropped
==6887==
==6887== HEAP SUMMARY:
==6887== in use at exit: 640 bytes in 10 blocks
==6887== total heap usage: 30 allocs, 20 frees, 4,433 bytes allocated
==6887==
==6887== Searching for pointers to 10 not-freed blocks
==6887== Checked 107,320 bytes
==6887==
==6887== 640 bytes in 10 blocks are definitely lost in loss record 1 of 1
==6887== at 0x4C320A6: memalign (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==6887== by 0x10CB3F: minimal_test::alloc_array (main.rs:11)
==6887== by 0x10CDDC: minimal_test::Vec<T>::pushBack (main.rs:35)
==6887== by 0x10E1BB: minimal_test::main (main.rs:85)
==6887== by 0x10C2DF: std::rt::lang_start::{{closure}} (rt.rs:67)
==6887== by 0x1165B2: {{closure}} (rt.rs:52)
==6887== by 0x1165B2: std::panicking::try::do_call (panicking.rs:305)
==6887== by 0x117D16: __rust_maybe_catch_panic (lib.rs:86)
==6887== by 0x116F3F: try<i32,closure-0> (panicking.rs:281)
==6887== by 0x116F3F: catch_unwind<closure-0,i32> (panic.rs:394)
==6887== by 0x116F3F: std::rt::lang_start_internal (rt.rs:51)
==6887== by 0x10C2B8: std::rt::lang_start (rt.rs:67)
==6887== by 0x10E259: main (in minimal-test/target/debug/minimal-test)
==6887==
==6887== LEAK SUMMARY:
==6887== definitely lost: 640 bytes in 10 blocks
==6887== indirectly lost: 0 bytes in 0 blocks
==6887== possibly lost: 0 bytes in 0 blocks
==6887== still reachable: 0 bytes in 0 blocks
==6887== suppressed: 0 bytes in 0 blocks
==6887==
==6887== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
==6887== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

最佳答案

密切注意类型。

pub fn get(&self, idx: usize) -> &T {
self.get(i)的类型为 &T。因此 &mut self.get(i)的类型为 &mut &T。调用 drop_in_place将把 &mut &T强制转换为 *mut &T并删除一个 &T,该操作(由于共享引用未实现 Drop)没有任何作用。
self.get(i) as *const _ as *mut _&T转换为 *const T,然后转换为 *mut T调用drop_in_place会在调用<T as Drop>::drop时调用未定义的行为,后者接受&mut T,这很糟糕。

您不能通过共享引用来更改值(包括删除值)。通过原始指针进行转换无法实现。参见 Is there a way to make an immutable reference mutable?

Nomicon包含有关从头开始实现 Vec<T>的部分;我建议阅读。

关于rust - `&mut retval`和 `retval as *const T as *mut T`有什么区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60943462/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com