CodeBlanks Logo Icon CodeBlanks

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.

Başlangıç kodu

main.rs
use std::ffi::c_void;

fn main() {
    // buraya yaz
}

Örnek çözüm

main.rs
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);
}

Beklenen çıktı

10
serbest bırakıldı

Soru ve cevaplar

Dersin sorularını cevaplarıyla birlikte inceleyebilirsin. Kendini denemek istersen dersi interaktif olarak çöz.

1 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ı Doğru cevap
  • Box yavaştır
  • Doğrudur

Açıklama: Kural: belleği hangi taraf ayırdıysa o taraf serbest bırakır.

2 Serbest bırak

Soru
impl Drop for CTampon {
    fn drop(&mut self) {
        unsafe { ____(self.p as *mut c_void) };
    }
}
Cevap
impl Drop for CTampon {
    fn drop(&mut self) {
        unsafe { free(self.p as *mut c_void) };
    }
}

Açıklama: malloc ile ayrılan bellek C'nin free fonksiyonuyla serbest bırakılır.

3 Adım ve sorumlu

Kavram Anlamı
malloc Ayırır
Drop::drop free çağırır
p.is_null() Ayırma başarısız
dilim() Güvenli erişim

İleri seviye bölümündeki tüm dersler