Table des matières
Box<T> est un smart pointer en Rust qui fournit l'allocation heap pour une valeur de type T. C'est la façon la plus simple de stocker des données sur le heap, offrant des garanties d'ownership et memory safety sans overhead runtime.
Qu'est-ce que Box ?
- Allocation Heap : Déplace les données du stack vers le heap.
let x = Box::new(42); // `42` est stocké sur le heap - Ownership :
Box<T>possède les données et assure qu'elles sont droppées quand leBoxsort du scope. - Taille Fixe : Le
Boxlui-même est un pointeur (usize) avec une taille stack connue, même siTest dynamically sized (ex :Box<dyn Trait>).
Quand Utiliser Box
1. Types Récursifs (ex : Listes Chaînées)
Rust nécessite des tailles connues au moment de la compilation, mais les types récursifs (comme arbres ou listes) seraient infiniment grands sans indirection.
enum List {
Cons(i32, Box<List>), // Sans `Box`, ce serait invalide
Nil,
}
2. Grosses Données (Éviter Stack Overflow)
Déplacer de grosses structs (ex : buffer 1MB) vers le heap prévient les stack overflows.
let big_data = Box::new([0u8; 1_000_000]); // Array heap-allocated
3. Trait Objects (dyn Trait)
Stocker des types hétérogènes derrière une interface trait pour dynamic dispatch.
trait Animal { fn speak(&self); }
struct Cat;
impl Animal for Cat {
fn speak(&self) { println!("Meow"); }
}
let animals: Vec<Box<dyn Animal>> = vec![Box::new(Cat)]; // Dynamic dispatch
4. Transférer Ownership Entre Threads
Box peut être utilisé avec std::thread::spawn pour move des données owned vers un autre thread.
let x = Box::new(42);
std::thread::spawn(move || {
println!("{}", x); // `x` est moved dans le thread
});
Comment Box Diffère d'Autres Pointeurs
| Type | Ownership | Cas d'Usage |
|---|---|---|
Box<T> |
Owned (unique) | Allocation heap, types récursifs |
&T/&mut T |
Borrowed | Références temporaires |
Rc<T> |
Shared (reference-counted) | Propriétaires multiples en single-threaded |
Arc<T> |
Shared (atomic refcount) | Propriétaires multiples thread-safe |
Garanties Memory Safety
- Pas de
free()manuel : Désalloue automatiquement quandBoxsort du scope. - Pas de null pointers :
Boxne peut pas être null (contrairement aux raw pointers). - Pas de leaks : Le compilateur applique les règles d'ownership.
Exemple : Box vs Stack Allocation
// Stack (échoue si trop gros)
// let arr = [0u8; 10_000_000]; // Probablement stack overflow
// Heap (fonctionne)
let arr = Box::new([0u8; 10_000_000]); // Sûr
Points Clés
✅ Utilise Box<T> quand tu as besoin :
- D'allocation heap pour données larges ou récursives.
- De trait objects (
dyn Trait). - D'ownership explicite avec pointeur taille fixe.
🚫 Évite si :
- Tu as seulement besoin d'une référence (
&T). - Tu as besoin d'ownership partagé (utilise
RcouArcà la place).
Expérience de Pensée : Que se passe-t-il si tu essaies de Box une valeur déjà sur le heap ?
Réponse : C'est ok—ça ajoute juste une autre indirection de pointeur, car le Box pointera vers la nouvelle allocation heap.