Table des matières
Le trait Drop en Rust permet une logique de cleanup personnalisée quand une valeur sort du scope, fournissant une gestion déterministe des ressources similaire au RAII de C++ (Resource Acquisition Is Initialization). Il assure la memory safety et la désallocation appropriée des ressources sans garbage collector.
Qu'est-ce que le Trait Drop ?
Le trait Drop définit une seule méthode, drop, qui est automatiquement appelée quand une valeur est détruite :
trait Drop {
fn drop(&mut self); // Appelée automatiquement quand la valeur est détruite
}
Comment ça Fonctionne
- Invocation Automatique : Rust appelle
dropquand :- Une variable sort du scope.
- L'ownership est transférée (ex : moved dans une fonction).
- Explicitement droppée via
std::mem::drop.
- Ordre LIFO : Les valeurs sont droppées dans l'ordre inverse de leur déclaration (comportement stack-like).
Exemple : Drop Basique :
struct Resource {
id: u32,
}
impl Drop for Resource {
fn drop(&mut self) {
println!("Dropping resource {}", self.id);
}
}
fn main() {
let _res1 = Resource { id: 1 }; // Droppée en second
let _res2 = Resource { id: 2 }; // Droppée en premier
}
Sortie :
Dropping resource 2
Dropping resource 1
Quand Implémenter Drop Manuellement
1. Cleanup de Ressources
Pour gérer des ressources non-mémoire comme fichiers, sockets, ou locks :
struct DatabaseConnection {
// Détails de connexion
}
impl Drop for DatabaseConnection {
fn drop(&mut self) {
self.close(); // Assure que la connexion est libérée
}
}
2. Gestion Mémoire Personnalisée
Pour intégrer avec FFI ou code unsafe :
struct RawBuffer {
ptr: *mut u8,
}
impl Drop for RawBuffer {
fn drop(&mut self) {
unsafe { libc::free(self.ptr as *mut _); } // Libère manuellement mémoire heap
}
}
3. Logging/Télémétrie
Pour tracker le cycle de vie d'objets :
struct MetricsTracker {
start: std::time::Instant,
}
impl Drop for MetricsTracker {
fn drop(&mut self) {
log::info!("Tracker dropped after {}ms", self.start.elapsed().as_millis());
}
}
Règles Clés
- Pas d'Appels Explicites : Appelle rarement
dropdirectement ; utilisestd::mem::droppour explicitement drop une valeur. - Pas de Panics : Évite de paniquer dans
drop, car cela peut mener à des double-drops ou arrêts de programme. - Auto Traits : Les types implémentant
Dropne peuvent pas êtreCopy.
Drop vs. Copy/Clone
| Trait | But | Mutuellement Exclusif ? |
|---|---|---|
Drop |
Logique de cleanup | Oui (ne peut pas être Copy) |
Copy |
Copie bitwise | Oui |
Clone |
Deep copy explicite | Non |
Avancé : #[may_dangle] (Nightly)
Pour les types génériques où T pourrait ne pas avoir besoin d'être droppé (unsafe) :
unsafe impl<#[may_dangle] T> Drop for MyBox<T> {
fn drop(&mut self) { /* ... */ }
}
Quand Ne Pas Utiliser Drop
- Données Simples : Pas besoin de
Dropsi le cleanup est géré par d'autres types (ex :Box,Vec). - Thread-Safety : Utilise
Arc+Mutexau lieu de locking manuel dansdrop.
Points Clés
✅ Utilise Drop pour :
- Cleanup de ressources (fichiers, locks, mémoire).
- Garanties FFI/safety-critical.
- Debugging/profiling.
🚫 Évite :
- Réimplémenter de la logique fournie par Rust (ex : désallocation de
Box). - Opérations complexes qui pourraient paniquer.
Exemple Réel : Le type MutexGuard utilise Drop pour libérer les locks automatiquement :
{
let guard = mutex.lock(); // Lock acquis
// ...
} // `guard` dropped ici → lock libéré
Expérimente : Que se passe-t-il si tu appelles mem::forget sur un type avec Drop ?
Réponse : Le destructeur ne s'exécutera pas, causant potentiellement une fuite de ressource (ex : fichiers non fermés ou mémoire non libérée).