Мне трудно понять, почему следующий код имеет 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);
}
}
Valgrind:
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)