rust / expert
Snippet
Manuelle Allokation benutzerdefinierter dynamisch skalierter Typen auf dem Heap
Dynamisch skalierte Typen (DSTs) wie Slices können nicht einfach auf dem Stack erstellt werden. Über die Standard-Allocator-API können wir benutzerdefinierte DSTs manuell erstellen, indem wir Layouts zusammenführen, Speicher allozieren und einen Fat-Pointer mittels slice_from_raw_parts_mut zusammensetzen.
snippet.rs
rust
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
use std::alloc::{alloc, Layout};use std::ptr;#[repr(C)]struct CustomBuffer {id: u64,data: [u8],}impl CustomBuffer {fn new(id: u64, slice: &[u8]) -> Box<Self> {let header_layout = Layout::new::<u64>();let array_layout = Layout::array::<u8>(slice.len()).unwrap();let (layout, _) = header_layout.extend(array_layout).unwrap();let layout = layout.pad_to_align();unsafe {let raw_ptr = alloc(layout);if raw_ptr.is_null() {std::alloc::handle_alloc_error(layout);}let dst_ptr = ptr::slice_from_raw_parts_mut(raw_ptr, slice.len()) as *mut CustomBuffer;ptr::write(ptr::addr_of_mut!((*dst_ptr).id), id);ptr::copy_nonoverlapping(slice.as_ptr(), ptr::addr_of_mut!((*dst_ptr).data) as *mut u8, slice.len());Box::from_raw(dst_ptr)}}}
Erklärung
1
let (layout, _) = header_layout.extend(array_layout).unwrap();
Kombiniert das statische Header-Layout und das dynamische Slice-Layout unter Berücksichtigung von Overflows.
2
let dst_ptr = ptr::slice_from_raw_parts_mut(raw_ptr, slice.len()) as *mut CustomBuffer;
Generiert einen Fat-Pointer, der sowohl die Speicheradresse als auch die Länge des Slice-Endes enthält.
3
Box::from_raw(dst_ptr)
Konvertiert den rohen Fat-Pointer zurück in eine verwaltete Box, was eine korrekte Deallokation garantiert.