Rust
Drop ve cleanup
FFI'da bellek temizliği ve Drop trait'ini öğrenirsin.
Drop ve cleanup
C kütüphaneleri genellikle bir "oluştur" ve bir "serbest bırak" fonksiyonu sunar. Rust sarmalayıcısında serbest bırakma Drop içine konur; böylece kullanıcı onu unutamaz ve hata ya da panic durumunda da çalışır:
unsafe extern "C" {
fn malloc(n: usize) -> *mut c_void;
fn free(p: *mut c_void);
}
struct CTampon {
p: *mut u8,
n: usize,
}
impl Drop for CTampon {
fn drop(&mut self) {
// SAFETY: p malloc'tan geldi ve yalnızca burada serbest bırakılır.
unsafe { free(self.p as *mut c_void) };
}
}
Güvenli arayüz
Ham işaretçiyi dışarı vermeden dilim üzerinden erişim sunmak, kullanımı güvenli yapar:
impl CTampon {
fn new(n: usize) -> Option<Self> {
let p = unsafe { malloc(n) } as *mut u8;
if p.is_null() { None } else { Some(Self { p, n }) }
}
fn dilim(&mut self) -> &mut [u8] {
// SAFETY: p, n baytlık geçerli bir bölgeyi gösterir.
unsafe { std::slice::from_raw_parts_mut(self.p, self.n) }
}
}
malloc başarısız olursa boş işaretçi döner; bunu Option ile ifade etmek kullanıcıyı denetim yapmaya zorlar.
Uygulama C tamponu
Yukarıdaki CTampon türünü (new, dilim, Drop) yaz; Drop serbest bıraktıktan sonra serbest bırakıldı yazdırsın. 4 baytlık bir tampon ayır, baytlara 1'den 4'e kadar değer yaz ve toplamlarını yazdır.
Örnek çözümü göster
use std::ffi::c_void;
unsafe extern "C" {
fn malloc(n: usize) -> *mut c_void;
fn free(p: *mut c_void);
}
struct CTampon {
p: *mut u8,
n: usize,
}
impl CTampon {
fn new(n: usize) -> Option<Self> {
// SAFETY: malloc herhangi bir boyut için çağrılabilir.
let p = unsafe { malloc(n) } as *mut u8;
if p.is_null() {
None
} else {
Some(Self { p, n })
}
}
fn dilim(&mut self) -> &mut [u8] {
// SAFETY: p, n baytlık geçerli bir bölgeyi gösterir.
unsafe { std::slice::from_raw_parts_mut(self.p, self.n) }
}
}
impl Drop for CTampon {
fn drop(&mut self) {
// SAFETY: p malloc'tan geldi ve yalnızca burada serbest bırakılır.
unsafe { free(self.p as *mut c_void) };
println!("serbest bırakıldı");
}
}
fn main() {
let mut t = CTampon::new(4).unwrap();
for (i, b) in t.dilim().iter_mut().enumerate() {
*b = i as u8 + 1;
}
let toplam: u32 = t.dilim().iter().map(|&b| b as u32).sum();
println!("{}", toplam);
}
Kendini test et
-
C'den gelen belleği Rust'ın <code>Box::from_raw</code> ile serbest bırakmak neden yanlıştır?
- Derlenmez
- Bellek farklı bir ayırıcıdan geldi; ayıran taraf serbest bırakmalı
- Box yavaştır
- Doğrudur
Cevabı göster
Bellek farklı bir ayırıcıdan geldi; ayıran taraf serbest bırakmalı — Kural: belleği hangi taraf ayırdıysa o taraf serbest bırakır.
-
Serbest bırak
impl Drop for CTampon {
fn drop(&mut self) {
unsafe { ____(self.p as *mut c_void) };
}
}
Cevabı göster
impl Drop for CTampon {
fn drop(&mut self) {
unsafe { free(self.p as *mut c_void) };
}
}
-
Adım ve sorumlu
- malloc
- Ayırır
- Drop::drop
- free çağırır
- p.is_null()
- Ayırma başarısız
- dilim()
- Güvenli erişim
Sıradaki ders: Özet - FFI