Soru geçmişi:
Rust'ta, çöp toplayıcısı olmadan kaynak yönetimi, nesnelerin sahiplik ve yaşam döngüsü ile ilgili sıkı kurallar sayesinde mümkün hale gelmiştir. Kaynakların otomatik olarak serbest bırakılması (örneğin, dosya tanıtıcıları, soketler, üçüncü taraf kütüphanelerden bellek) için, dilin tasarımı aşamasından itibaren Drop trait'i tanımlanmıştır. Bu, nesnenin yaşam döngüsünün sona ermesiyle "tepki vermenin" temel yolu olup, kaynakların işletim sistemine geri devredilmesi veya belleğin serbest bırakılması için uygulanır.
Problem:
Normal Rust türleri kendi kaynaklarını otomatik olarak temizler, ancak bir yapı manuel serbest bırakma gerektiren bir kaynağı (örneğin, açık bir dosya veya tehlikeli bir işaretçi) sakladığında, geliştiricinin isteksizliği veya unutkanlığı, kaynak sızıntılarına veya yarış durumlarına neden olabilir. Eğer Drop yanlış bir şekilde uygulanırsa (örneğin, belleğin çift serbest bırakılma olasılığını göz önünde bulundurmamak gibi) bu, çalışma zamanı hatalarına yol açabilir.
Çözüm:
Drop trait'i, bir değerin yok edilmesi sırasında otomatik olarak çağrılan özel bir drop(&mut self) metodunu tanımlamanıza olanak tanır. Bu, bir nesne görünüm dışına çıktığında kaynakları serbest bırakmak için uygundur. Kaynağı (örneğin, dosyayı kapatmak) yalnızca burada serbest bırakmak gerektiğini unutmamak önemlidir.
Kod örneği:
struct RawFile { handle: *mut libc::FILE, } impl Drop for RawFile { fn drop(&mut self) { if !self.handle.is_null() { unsafe { libc::fclose(self.handle); } } } }
Anahtar özellikler:
drop yöntemi açıkça çağrılmaz - yalnızca derleyici tarafından çağrılır.Drop, non-Rust kaynağını elinde bulunduran bir yapı için uygulanır.Drop, mem::forget veya panic! aracılığıyla sızıntı durumunda (unwinding dışında) varsayılan olarak tetiklenmez.Bir nesne için kaynağı daha erken serbest bırakmak amacıyla drop'ı açıkça çağırabilir miyiz?
Hayır, drop metodunu doğrudan çağırmak (&obj.drop()) yasaktır - yalnızca std::mem::drop(obj) fonksiyonu aracılığıyla, nesnenin sahipliğini alarak otomatik olarak drop'ı çağırabiliriz. drop()'ı doğrudan çağırmak derlenmez.
Kod örneği:
fn main() { let f = File::open("foo.txt").unwrap(); // drop(&mut f); // Derleme hatası! std::mem::drop(f); // Doğru: dosyanın kapatılması }
Drop'a sahip bir yapı memcpy veya move işlemine tabi olursa ne olur? Destructor iki kez çağrılmaz mı?
Hayır, destructor, bir nesnenin yaşam döngüsü boyunca tam olarak bir kez çağrılır ve derleyici bunu takip eder. Ancak, "ham" byte'ları yapıdan unsafe bir şekilde kopyalarken veya mem::forget kullanıldığında, drop hiç çağrılmayabilir - buradan tehlike doğar.
Aynı tür için hem Drop hem de Copy'ı aynı anda uygulamak mümkün mü?
Hayır, derleyici bu kombinasyonu yasaklar: Drop'ı uygulayan bir tür Copy olamaz, böylece destructor'un bir kez çağrılmasını garanti eder ve çift serbest bırakma olasılığını ortadan kaldırır.
drop yönteminin doğrudan çağrılması (yasaktır)Drop'ı unutarak serbest bırakılmamış kaynak veya açık dosyaCopy ile aynı anda Drop'ı uygulama (Derleme hatası)drop sırasının kritik olduğu karmaşık sahiplik zincirleriBir programcı, açık bir dosyayla çalışmak için basit bir sarmalayıcı yazdı, ancak Drop'ı uygulamayı ve nesne silindiğinde tanıtıcıyı kapatmayı unuttu.
Artılar:
Eksiler:
Geliştirici, dosya tanıtıcısı sarmalayıcısı için Drop'ı uygulayarak, dosyayı drop içinde açıkça kapatır. Artık bu yapının değişkenlerinden herhangi biri işlev dışına çıktığında veya panic yaşandığında kaynak garantili olarak serbest bırakılır.
Artılar:
Eksiler:
Copy'nın olamayacağı hatırlanmalıdır.